Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
|''URL:''|http://tiddlywiki.abego-software.de/|
|''Description:''|UdoBorkowski's Extensions for TiddlyWiki|
|''Author:''|UdoBorkowski|
/***
|Name|AttachFilePlugin|
|Source|http://www.TiddlyTools.com/#AttachFilePlugin|
|Documentation|http://www.TiddlyTools.com/#AttachFilePluginInfo|
|Version|3.9.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|AttachFilePluginFormatters, AttachFileMIMETypes|
|Overrides||
|Description|Store binary files as base64-encoded tiddlers with fallback links for separate local and/or remote file storage|
Store or link binary files (such as jpg, gif, pdf or even mp3) within your TiddlyWiki document and then use them as images or links from within your tiddler content.
> Important note: As of version 3.6.0, in order to //render// images and other binary attachments created with this plugin, you must also install [[AttachFilePluginFormatters]], which extends the behavior of the TiddlyWiki core formatters for embedded images ({{{[img[tooltip|image]]}}}), linked embedded images ({{{[img[tooltip|image][link]]}}}), and external/"pretty" links ({{{[[label|link]]}}}), so that these formatter will process references to attachment tiddlers as if a normal file reference had been provided. |
!!!!!Documentation
>see [[AttachFilePluginInfo]]
!!!!!Inline interface (live)
>see [[AttachFile]] (shadow tiddler)
><<tiddler AttachFile>>
!!!!!Revisions
<<<
2008.07.21 [3.9.0] Fixup for FireFox 3: use HTML with separate text+button control instead of type='file' control
|please see [[AttachFilePluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.AttachFilePlugin= {major: 3, minor: 9, revision: 0, date: new Date(2008,7,21)};
// shadow tiddler
config.shadowTiddlers.AttachFile="<<attach inline>>";
// add 'attach' backstage task (insert before built-in 'importTask')
if (config.tasks) { // for TW2.2b or above
config.tasks.attachTask = {
text: "attach",
tooltip: "Attach a binary file as a tiddler",
content: "<<attach inline>>"
}
config.backstageTasks.splice(config.backstageTasks.indexOf("importTask"),0,"attachTask");
}
config.macros.attach = {
// // lingo
//{{{
label: "attach file",
tooltip: "Attach a file to this document",
linkTooltip: "Attachment: ",
typeList: "AttachFileMIMETypes",
titlePrompt: " enter tiddler title...",
MIMEPrompt: "<option value=''>select MIME type...</option><option value='editlist'>[edit list...]</option>",
localPrompt: " enter local path/filename...",
URLPrompt: " enter remote URL...",
tiddlerErr: "Please enter a tiddler title",
sourceErr: "Please enter a source path/filename",
storageErr: "Please select a storage method: embedded, local or remote",
MIMEErr: "Unrecognized file format. Please select a MIME type",
localErr: "Please enter a local path/filename",
URLErr: "Please enter a remote URL",
fileErr: "Invalid path/file or file not found",
sourceReport: "| source file:|{{{%0}}}|\n",
nosourceReport: "| source file:|//none//|\n",
dateReport: "| attached on:|%0 by %1|\n",
notesReport: "| description:|%0|\n",
dataReport: "| embedded:|[[%0|%0]] - {{{type=%1, size=%2 bytes, encoded=%3 bytes}}}|\n",
nodataReport: "| embedded:|//none//|\n",
localReport: "| local file:|/%LOCAL_LINK%/[[%0|%1]]|\n",
nolocalReport: "| local file:|//none//|\n",
URLReport: "| remote link:|/%REMOTE_LINK%/[[%0|%0]]|\n",
noURLReport: "| remote link:|//none//|\n",
imageReport: "image\n<<<\nusage: {{{[img[tooltip|%0]] or [img[tooltip|%0][link]]}}}\n[img[tooltip|%0]]\n<<<\n",
dataBlock: "\n/% DO NOT EDIT BELOW THIS POINT\n---BEGIN_DATA---\n%0;base64,\n%1\n---END_DATA---\n%/",
//}}}
// // macro definition
//{{{
handler:
function(place,macroName,params) {
if (params && !params[0]) { createTiddlyButton(place,this.label,this.tooltip,this.toggleAttachPanel); return; }
var id=params.shift();
this.createAttachPanel(place,id+"_attachPanel",params);
document.getElementById(id+"_attachPanel").style.position="static";
document.getElementById(id+"_attachPanel").style.display="block";
},
//}}}
//{{{
createAttachPanel:
function(place,panel_id,params) {
if (!panel_id || !panel_id.length) var panel_id="_attachPanel";
// remove existing panel (if any)
var panel=document.getElementById(panel_id); if (panel) panel.parentNode.removeChild(panel);
// set styles for this panel
setStylesheet(this.css,"attachPanel");
// create new panel
var title=""; if (params && params[0]) title=params.shift();
var types=this.MIMEPrompt+this.formatListOptions(store.getTiddlerText(this.typeList)); // get MIME types
panel=createTiddlyElement(place,"span",panel_id,"attachPanel",null);
var html=this.html.replace(/%id%/g,panel_id);
html=html.replace(/%title%/g,title);
html=html.replace(/%disabled%/g,title.length?"disabled":"");
html=html.replace(/%IEdisabled%/g,config.browser.isIE?"disabled":"");
html=html.replace(/%types%/g,types);
panel.innerHTML=html;
if (config.browser.isGecko) { // FF3 FIXUP
document.getElementById("attachSource").style.display="none";
document.getElementById("attachFixPanel").style.display="block";
}
return panel;
},
//}}}
//{{{
toggleAttachPanel:
function (e) {
if (!e) var e = window.event;
var parent=resolveTarget(e).parentNode;
var panel = document.getElementById("_attachPanel");
if (panel==undefined || panel.parentNode!=parent)
panel=config.macros.attach.createAttachPanel(parent,"_attachPanel");
var isOpen = panel.style.display=="block";
if(config.options.chkAnimate)
anim.startAnimating(new Slider(panel,!isOpen,e.shiftKey || e.altKey,"none"));
else
panel.style.display = isOpen ? "none" : "block" ;
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
return(false);
},
//}}}
//{{{
formatListOptions:
function(text) {
if (!text || !text.trim().length) return "";
// get MIME list content from text
var parts=text.split("\n----\n");
var out="";
for (var p=0; p<parts.length; p++) {
var lines=parts[p].split("\n");
var label=lines.shift(); // 1st line=display text
var value=lines.shift(); // 2nd line=item value
out +='<option value="%1">%0</option>'.format([label,value]);
}
return out;
},
//}}}
// // interface definition
//{{{
css:
".attachPanel { display: none; position:absolute; z-index:10; width:35em; right:105%; top:0em;\
background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em; text-align:left }\
.attachPanel form { display:inline;border:0;padding:0;margin:0; }\
.attachPanel select { width:99%;margin:0px;font-size:8pt;line-height:110%;}\
.attachPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
.attachPanel textarea { width:98%;margin:0px;height:2em;font-size:8pt;line-height:110%}\
.attachPanel table { width:100%;border:0;margin:0;padding:0;color:inherit; }\
.attachPanel tbody, .attachPanel tr, .attachPanel td { border:0;margin:0;padding:0;color:#000; }\
.attachPanel .box { border:1px solid black; padding:.3em; margin:.3em 0px; background:#f8f8f8; -moz-border-radius:5px;-webkit-border-radius:5px; }\
.attachPanel .chk { width:auto;border:0; }\
.attachPanel .btn { width:auto; }\
.attachPanel .btn2 { width:49%; }\
",
//}}}
//{{{
html:
'<form>\
attach from source file\
<input type="file" id="attachSource" name="source" size="56"\
onChange="config.macros.attach.onChangeSource(this)">\
<div id="attachFixPanel" style="display:none"><!-- FF3 FIXUP -->\
<input type="text" id="attachFixSource" style="width:90%"\
title="Enter a path/file to attach"\
onChange="config.macros.attach.onChangeSource(this);">\
<input type="button" style="width:7%" value="..."\
title="Enter a path/file to attach"\
onClick="config.macros.attach.askForFilename(document.getElementById(\'attachFixSource\'));">\
</div><!--end FF3 FIXUP-->\
<div class="box">\
<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
embed data <input type=checkbox class=chk name="useData" %IEdisabled% \
onclick="if (!this.form.MIMEType.value.length)\
this.form.MIMEType.selectedIndex=this.checked?1:0; "> \
</td><td style="border:0">\
<select size=1 name="MIMEType" \
onchange="this.title=this.value; if (this.value==\'editlist\')\
{ this.selectedIndex=this.form.useData.checked?1:0; story.displayTiddler(null,config.macros.attach.typeList,2); return; }">\
<option value=""></option>\
%types%\
</select>\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
local link <input type=checkbox class=chk name="useLocal"\
onclick="this.form.local.value=this.form.local.defaultValue=this.checked?config.macros.attach.localPrompt:\'\';"> \
</td><td style="border:0">\
<input type=text name="local" size=15 autocomplete=off value=""\
onchange="this.form.useLocal.checked=this.value.length" \
onkeyup="this.form.useLocal.checked=this.value.length" \
onfocus="if (!this.value.length) this.value=config.macros.attach.localPrompt; this.select()">\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
remote link <input type=checkbox class=chk name="useURL"\
onclick="this.form.URL.value=this.form.URL.defaultValue=this.checked?config.macros.attach.URLPrompt:\'\';\"> \
</td><td style="border:0">\
<input type=text name="URL" size=15 autocomplete=off value=""\
onfocus="if (!this.value.length) this.value=config.macros.attach.URLPrompt; this.select()"\
onchange="this.form.useURL.checked=this.value.length;"\
onkeyup="this.form.useURL.checked=this.value.length;">\
</td></tr></table>\
</div>\
<table style="border:0"><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
attach as \
</td><td style="border:0" colspan=2>\
<input type=text name="tiddlertitle" size=15 autocomplete=off value="%title%"\
onkeyup="if (!this.value.length) { this.value=config.macros.attach.titlePrompt; this.select(); }"\
onfocus="if (!this.value.length) this.value=config.macros.attach.titlePrompt; this.select()" %disabled%>\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
description \
</td><td style="border:0" colspan=2>\
<input type=text name="notes" size=15 autocomplete=off>\
</td></tr><tr style="border:0"><td style="border:0;text-align:right;width:1%;white-space:nowrap">\
add tags \
</td><td style="border:0">\
<input type=text name="tags" size=15 autocomplete=off value="" onfocus="this.select()">\
</td><td style="width:40%;text-align:right;border:0">\
<input type=button class=btn2 value="attach"\
onclick="config.macros.attach.onClickAttach(this)"><!--\
--><input type=button class=btn2 value="close"\
onclick="var panel=document.getElementById(\'%id%\'); if (panel) panel.parentNode.removeChild(panel);">\
</td></tr></table>\
</form>',
//}}}
// // control processing
//{{{
onChangeSource:
function(here) {
var form=here.form;
var list=form.MIMEType;
var theFilename = here.value;
var theExtension = theFilename.substr(theFilename.lastIndexOf('.')).toLowerCase();
// if theFilename is in current document folder, remove path prefix and use relative reference
var h=document.location.href; folder=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
if (theFilename.substr(0,folder.length)==folder) theFilename='./'+theFilename.substr(folder.length);
else theFilename='file:///'+theFilename; // otherwise, use absolute reference
theFilename=theFilename.replace(/\\/g,"/"); // fixup: change \ to /
form.useLocal.checked = true;
form.local.value = theFilename;
form.useData.checked = !form.useData.disabled;
list.selectedIndex=1;
for (var i=0; i<list.options.length; i++) // find matching MIME type
if (list.options[i].value.indexOf(theExtension)!=-1) { list.selectedIndex = i; break; }
if (!form.tiddlertitle.disabled)
form.tiddlertitle.value=theFilename.substr(theFilename.lastIndexOf('/')+1); // get tiddlername from filename
},
//}}}
//{{{
onClickAttach:
function (here) {
clearMessage();
// get input values
var form=here.form;
var src=form.source; if (config.browser.isGecko) src=document.getElementById("attachFixSource");
var theDate=(new Date()).formatString(config.macros.timeline.dateFormat);
var theSource = src.value!=src.defaultValue?src.value:"";
var theTitle=form.tiddlertitle.value;
var theLocal = form.local.value!=form.local.defaultValue?form.local.value:"";
var theURL = form.URL.value!=form.URL.defaultValue?form.URL.value:"";
var theNotes = form.notes.value;
var theTags = "attachment excludeMissing "+form.tags.value;
var useData=form.useData.checked;
var useLocal=form.useLocal.checked;
var useURL=form.useURL.checked;
var theMIMEType = form.MIMEType.value.length?form.MIMEType.options[form.MIMEType.selectedIndex].text:"";
// validate checkboxes and get filename
if (useData) {
if (theSource.length) { if (!theLocation) var theLocation=theSource; }
else { alert(this.sourceErr); src.focus(); return false; }
}
if (useLocal) {
if (theLocal.length) { if (!theLocation) var theLocation = theLocal; }
else { alert(this.localErr); form.local.focus(); return false; }
}
if (useURL) {
if (theURL.length) { if (!theLocation) var theLocation = theURL; }
else { alert(this.URLErr); form.URL.focus(); return false; }
}
if (!(useData||useLocal||useURL))
{ form.useData.focus(); alert(this.storageErr); return false; }
if (!theLocation)
{ src.focus(); alert(this.sourceErr); return false; }
if (!theTitle || !theTitle.trim().length || theTitle==this.titlePrompt)
{ form.tiddlertitle.focus(); alert(this.tiddlerErr); return false; }
// if not already selected, determine MIME type based on filename extension (if any)
if (useData && !theMIMEType.length && theLocation.lastIndexOf('.')!=-1) {
var theExt = theLocation.substr(theLocation.lastIndexOf('.')).toLowerCase();
var theList=form.MIMEType;
for (var i=0; i<theList.options.length; i++)
if (theList.options[i].value.indexOf(theExt)!=-1)
{ var theMIMEType=theList.options[i].text; theList.selectedIndex=i; break; }
}
// attach the file
return this.createAttachmentTiddler(theSource, theDate, theNotes, theTags, theTitle,
useData, useLocal, useURL, theLocal, theURL, theMIMEType);
},
getMIMEType:
function(src,def) {
var ext = src.substr(src.lastIndexOf('.')).toLowerCase();
var list=store.getTiddlerText(this.typeList);
if (!list || !list.trim().length) return def;
// get MIME list content from tiddler
var parts=list.split("\n----\n");
for (var p=0; p<parts.length; p++) {
var lines=parts[p].split("\n");
var mime=lines.shift(); // 1st line=MIME type
var match=lines.shift(); // 2nd line=matching extensions
if (match.indexOf(ext)!=-1) return mime;
}
return def;
},
createAttachmentTiddler:
function (theSource, theDate, theNotes, theTags, theTitle,
useData, useLocal, useURL, theLocal, theURL, theMIMEType, noshow) {
// encode the data
if (useData) {
if (!theMIMEType.length) {
alert(this.MIMEErr);
form.MIMEType.selectedIndex=1; form.MIMEType.focus();
return false;
}
var theData = this.readFile(theSource); if (!theData) { return false; }
displayMessage('encoding '+theSource);
var theEncoded = this.encodeBase64(theData);
displayMessage('file size='+theData.length+' bytes, encoded size='+theEncoded.length+' bytes');
}
// generate tiddler and refresh
var theText = "";
theText +=theSource.length?this.sourceReport.format([theSource]):this.nosourceReport;
theText +=this.dateReport.format([theDate,config.options.txtUserName]);
theText +=theNotes.length?this.notesReport.format([theNotes]):"";
theText +=useData?this.dataReport.format([theTitle,theMIMEType,theData.length,theEncoded.length]):this.nodataReport;
theText +=useLocal?this.localReport.format([theLocal,theLocal.replace(/\\/g,"/")]):this.nolocalReport;
theText +=useURL?this.URLReport.format([theURL]):this.noURLReport;
theText +=(theMIMEType.substr(0,5)=="image")?this.imageReport.format([theTitle]):"";
theText +=useData?this.dataBlock.format([theMIMEType,theEncoded]):"";
store.saveTiddler(theTitle,theTitle,theText,config.options.txtUserName,new Date(),theTags);
var panel=document.getElementById("attachPanel"); if (panel) panel.style.display="none";
if (!noshow) { story.displayTiddler(null,theTitle); story.refreshTiddler(theTitle,null,true); }
displayMessage('attached "'+theTitle+'"');
return true;
},
//}}}
// // base64 conversion
//{{{
encodeBase64:
function (theData) {
if (!theData) return null;
// encode as base64
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var out="";
var chr1,chr2,chr3="";
var enc1,enc2,enc3,enc4="";
for (var count=0,i=0; i<theData.length; ) {
chr1=theData.charCodeAt(i++);
chr2=theData.charCodeAt(i++);
chr3=theData.charCodeAt(i++);
enc1=chr1 >> 2;
enc2=((chr1 & 3) << 4) | (chr2 >> 4);
enc3=((chr2 & 15) << 2) | (chr3 >> 6);
enc4=chr3 & 63;
if (isNaN(chr2)) enc3=enc4=64;
else if (isNaN(chr3)) enc4=64;
out+=keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4);
chr1=chr2=chr3=enc1=enc2=enc3=enc4="";
count+=4; if (count>60) { out+='\n'; count=0; } // add line break every 60 chars for readability
}
return out;
},
decodeBase64: function(input) {
var out="";
var chr1,chr2,chr3;
var enc1,enc2,enc3,enc4;
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input=input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1=keyStr.indexOf(input.charAt(i++));
enc2=keyStr.indexOf(input.charAt(i++));
enc3=keyStr.indexOf(input.charAt(i++));
enc4=keyStr.indexOf(input.charAt(i++));
chr1=(enc1 << 2) | (enc2 >> 4);
chr2=((enc2 & 15) << 4) | (enc3 >> 2);
chr3=((enc3 & 3) << 6) | enc4;
out=out+String.fromCharCode(chr1);
if (enc3!=64) out=out+String.fromCharCode(chr2);
if (enc4!=64) out=out+String.fromCharCode(chr3);
} while (i<input.length);
return out;
},
//}}}
// // I/O functions
//{{{
readFile: // read local BINARY file data
function(filePath) {
if(!window.Components) { return null; }
try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
catch(e) { alert("access denied: "+filePath); return null; }
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
try { file.initWithPath(filePath); } catch(e) { alert("cannot read file - invalid path: "+filePath); return null; }
if (!file.exists()) { alert("cannot read file - not found: "+filePath); return null; }
var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
inputStream.init(file, 0x01, 00004, null);
var bInputStream = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
bInputStream.setInputStream(inputStream);
return(bInputStream.readBytes(inputStream.available()));
},
//}}}
//{{{
writeFile:
function(filepath,data) {
// TBD: decode base64 and write BINARY data to specified local path/filename
return(false);
},
//}}}
//{{{
askForFilename: // for FF3 fixup
function(target) {
var msg=config.messages.selectFile;
if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
// get local path for current document
var path=getLocalPath(document.location.href);
var p=path.lastIndexOf("/"); if (p==-1) p=path.lastIndexOf("\\"); // Unix or Windows
if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
var file=""
var result=window.mozAskForFilename(msg,path,file,true); // FF3 FIXUP ONLY
if (target && result.length) // set target field and trigger handling
{ target.value=result; target.onchange(); }
return result;
}
};
//}}}
//{{{
if (window.mozAskForFilename===undefined) { // also defined by CoreTweaks (for ticket #604)
window.mozAskForFilename=function(msg,path,file,mustExist) {
if(!window.Components) return false;
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel)
var result=picker.file.persistentDescriptor;
}
catch(ex) { displayMessage(ex.toString()); }
return result;
}
}
//}}}
/***
|Name|AttachFilePluginFormatters|
|Source|http://www.TiddlyTools.com/#AttachFilePluginFormatters|
|Version|3.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1.3|
|Type|plugin|
|Requires||
|Overrides|'image' and 'prettyLink' formatters, TiddlyWiki.prototype.getRecursiveTiddlerText|
|Description|run-time library for displaying attachment tiddlers|
This plugin provides "stand-alone" processing for //rendering// attachment tiddlers created by [[AttachFilePlugin]]. Attachment tiddlers are tagged with<<tag attachment>>and contain binary file content (e.g., jpg, gif, pdf, mp3, etc.) that has been stored directly as base64 text-encoded data or can be loaded from external files stored on a local filesystem or remote web server.
NOTE: This plugin does not include the "control panel" and supporting functions needed to //create// new attachment tiddlers. Those features are provided by [[AttachFilePlugin]], which can be installed while building your document, and then safely omitted to reduce the overall file size when you publish your finished document (assuming you don't intend to create any additional attachment tiddlers in that document)
!!!!!Formatters
<<<
This plugin extends the behavior of the following TiddlyWiki core "wikify()" formatters:
* embedded images: {{{[img[tooltip|image]]}}}
* linked embedded images: {{{[img[tooltip|image][link]]}}}
* external/"pretty" links: {{{[[label|link]]}}}
''Please refer to AttachFilePlugin (source: http://www.TiddlyTools.com/#AttachFilePlugin) for additional information.''
<<<
!!!!!Revisions
<<<
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.29 [3.7.0] more code reduction: removed upload handling from AttachFilePlugin (saves ~7K!)
2007.10.28 [3.6.0] removed duplicate formatter code from AttachFilePlugin (saves ~10K!) and updated documentation accordingly. This plugin ([[AttachFilePluginFormatters]]) is now //''required''// in order to display attached images/binary files within tiddler content.
2006.05.20 [3.4.0] through 2007.03.01 [3.5.3] sync with AttachFilePlugin
2006.05.13 [3.2.0] created from AttachFilePlugin v3.2.0
<<<
!!!!!Code
***/
// // version
//{{{
version.extensions.AttachFilePluginFormatters= {major: 3, minor: 7, revision: 0, date: new Date(2007,10,28)};
//}}}
//{{{
if (config.macros.attach==undefined) config.macros.attach= { };
//}}}
//{{{
if (config.macros.attach.isAttachment==undefined) config.macros.attach.isAttachment=function (title) {
var tiddler = store.getTiddler(title);
if (tiddler==undefined || tiddler.tags==undefined) return false;
return (tiddler.tags.indexOf("attachment")!=-1);
}
//}}}
//{{{
// test for local file existence
// Returns true/false without visible error display
// Uses Components for FF and ActiveX FSO object for MSIE
if (config.macros.attach.fileExists==undefined) config.macros.attach.fileExists=function(theFile) {
var found=false;
// DEBUG: alert('testing fileExists('+theFile+')...');
if(window.Components) {
try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
catch(e) { return false; } // security access denied
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
try { file.initWithPath(theFile); }
catch(e) { return false; } // invalid directory
found = file.exists();
}
else { // use ActiveX FSO object for MSIE
var fso = new ActiveXObject("Scripting.FileSystemObject");
found = fso.FileExists(theFile)
}
// DEBUG: alert(theFile+" "+(found?"exists":"not found"));
return found;
}
//}}}
//{{{
if (config.macros.attach.getAttachment==undefined) config.macros.attach.getAttachment=function(title) {
// extract embedded data, local and remote links (if any)
var startmarker="---BEGIN_DATA---\n";
var endmarker="\n---END_DATA---";
var pos=0; var endpos=0;
var text = store.getTiddlerText(title);
var embedded="";
var locallink="";
var remotelink="";
// look for embedded data, convert to data: URI
if ((pos=text.indexOf(startmarker))!=-1 && (endpos=text.indexOf(endmarker))!=-1)
embedded="data:"+(text.substring(pos+startmarker.length,endpos)).replace(/\n/g,'');
if (embedded.length && !config.browser.isIE)
return embedded; // use embedded data if any... except for IE, which doesn't support data URI
// no embedded data... fallback to local/remote reference links...
// look for 'attachment link markers'
if ((pos=text.indexOf("/%LOCAL_LINK%/"))!=-1)
locallink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));
if ((pos=text.indexOf("/%REMOTE_LINK%/"))!=-1)
remotelink=text.substring(text.indexOf("|",pos)+1,text.indexOf("]]",pos));
// document is being served remotely... use remote URL (if any) (avoids security alert)
if (remotelink.length && document.location.protocol!="file:")
return remotelink;
// local link only... return link without checking file existence (avoids security alert)
if (locallink.length && !remotelink.length)
return locallink;
// local link, check for file exist... use local link if found
if (locallink.length) {
if (this.fileExists(getLocalPath(locallink))) return locallink;
// maybe local link is relative... add path from current document and try again
var pathPrefix=document.location.href; // get current document path and trim off filename
var slashpos=pathPrefix.lastIndexOf("/"); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf("\\");
if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
if (this.fileExists(getLocalPath(pathPrefix+locallink))) return locallink;
}
// no embedded data, no local (or not found), fallback to remote URL (if any)
if (remotelink.length)
return remotelink;
return ""; // attachment URL doesn't resolve
}
//}}}
//{{{
if (config.macros.attach.init_formatters==undefined) config.macros.attach.init_formatters=function() {
if (this.initialized) return;
// find the formatter for "image" and replace the handler
for (var i=0; i<config.formatters.length && config.formatters[i].name!="image"; i++);
if (i<config.formatters.length) config.formatters[i].handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) // Simple bracketted link
{
var e = w.output;
if(lookaheadMatch[5])
{
var link = lookaheadMatch[5];
// ELS -------------
var external=config.formatterHelpers.isExternalLink(link);
if (external)
{
if (config.macros.attach.isAttachment(link))
{
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);
// ELS -------------
addClass(e,"imageLink");
}
var img = createTiddlyElement(e,"img");
if(lookaheadMatch[1])
img.align = "left";
else if(lookaheadMatch[2])
img.align = "right";
if(lookaheadMatch[3])
img.title = lookaheadMatch[3];
img.src = lookaheadMatch[4];
// ELS -------------
if (config.macros.attach.isAttachment(lookaheadMatch[4]))
img.src=config.macros.attach.getAttachment(lookaheadMatch[4]);
// ELS -------------
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
//}}}
//{{{
// find the formatter for "prettyLink" and replace the handler
for (var i=0; i<config.formatters.length && config.formatters[i].name!="prettyLink"; i++);
if (i<config.formatters.length) {
config.formatters[i].handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var e;
var text = lookaheadMatch[1];
if(lookaheadMatch[3]) {
// Pretty bracketted link
var link = lookaheadMatch[3];
if (config.macros.attach.isAttachment(link)) {
e = createExternalLink(w.output,link);
e.href=config.macros.attach.getAttachment(link);
e.title=config.macros.attach.linkTooltip+link;
}
else e = (!lookaheadMatch[2] && config.formatterHelpers.isExternalLink(link))
? createExternalLink(w.output,link)
: createTiddlyLink(w.output,link,false,null,w.isStatic);
} else {
e = createTiddlyLink(w.output,text,false,null,w.isStatic);
}
createTiddlyText(e,text);
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
} // if "prettyLink" formatter found
this.initialized=true;
}
//}}}
//{{{
config.macros.attach.init_formatters(); // load time init
//}}}
//{{{
if (TiddlyWiki.prototype.coreGetRecursiveTiddlerText==undefined) {
TiddlyWiki.prototype.coreGetRecursiveTiddlerText = TiddlyWiki.prototype.getRecursiveTiddlerText;
TiddlyWiki.prototype.getRecursiveTiddlerText = function(title,defaultText,depth) {
return config.macros.attach.isAttachment(title)?
config.macros.attach.getAttachment(title):this.coreGetRecursiveTiddlerText.apply(this,arguments);
}
}
//}}}
/***
|''Name:''|AutoRefreshPlugin|
|''Version:''|1.0.1 (2007-01-20)|
|''Type:''|plugin|
|''Source:''|http://tiddlywiki.abego-software.de/#AutoRefreshPlugin|
|''Author:''|Udo Borkowski (ub [at] abego-software [dot] de)|
|''Documentation:''|[[AutoRefreshPlugin Documentation|http://tiddlywiki.abego-software.de/#%5B%5BAutoRefreshPlugin%20Documentation%5D%5D]]|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''~CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.5.0.9 or better; Internet Explorer 6.0|
A tiddler containing the {{{<<autoRefresh...>>}}} macro is automatically refreshed (re-painted) whenever a tiddler changes.
!Syntax
{{{
<<autoRefresh [observeTiddler: tiddler ...]>>
}}}
|{{{observeTiddler}}}|(optional) when specified the refresh will only happen when one of the tiddlers specified is changed.|
!Source Code
***/
//{{{
if (!window.abego) window.abego = {};
// autoRefresh Macro =============================================================
//
(function() {
var REFRESHER_NAME = "abego_onEveryChange";
var tiddlersToRefresh = {}; // A set holding the names of tiddlers to be refreshed
var onEveryChangeRefresher = function(e,changeList) {
var tiddlerElem = story.findContainingTiddler(e);
if (!tiddlerElem) return false;
var title = tiddlerElem.getAttribute("tiddler");
if (!title) return false;
// if "observeTiddler" are specified we only refresh if one of the given
// tiddlers has changed.
var observedTiddlers = e.getAttribute("observedTiddlers");
if (observedTiddlers) {
var a = observedTiddlers.readBracketedList();
if (!changeList || !a.containsAny(changeList))
return;
}
// Refresh the tiddler asynchronously.
// This way we can avoid repeated refreshes (e.g. when a tiddler is renamed)
tiddlersToRefresh[title] = true;
setTimeout(function() {
// Refresh all tiddlers in tiddlersToRefresh
for(var title in tiddlersToRefresh)
story.refreshTiddler(title,null,true);
// We have refreshed all pending tiddlers. Clear the set.
tiddlersToRefresh = {};
}, 0);
return true;
}
config.refreshers[REFRESHER_NAME] = onEveryChangeRefresher;
config.macros.autoRefresh = {};
config.macros.autoRefresh.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
params = paramString.parseParams("observeTiddler",null,true,false,true); // allowEval, cascadeDefaults, names allowed
var e = createTiddlyElement(place,"span");
e.setAttribute("refresh",REFRESHER_NAME);
var observedTiddlers = params[0]["observeTiddler"];
if (observedTiddlers && observedTiddlers.length) {
var s = "[["+observedTiddlers.join("]] [[")+"]]";
e.setAttribute("observedTiddlers",s);
}
};
})();
//}}}
|''URL:''|http://tiddlywiki.bidix.info/|
|''Description:''|Repository for BidiX's TiddlyWiki Extensions|
|''Author:''|BidiX|
|''URL:''|http://bob.mcelrath.org/plugins.html|
|''Description:''|Bob McElrath's Plugins|
|''Author:''|BobMcElrath|
//~TiddlyWiklets:// {{small{([[more|http://lewcid.org/tiddlywiki-bookmarklets/]])}}}
*<script label="TiddlyInfo" title="display version number and last-modified date">
(function(){if(window.version&&window.version.title=='TiddlyWiki'){alert('TiddlyWiki version: '+version.major+'.'+version.minor+'.'+version.revision+(version.beta?' (beta '+version.beta+')':'')+'\nLast modified: '+document.lastModified);}return false;})()
</script>
//load remote plugins://
*<<tiddler LoadRemotePlugin with:
[[TiddlerTweakerPlugin]]
[[Load TiddlerTweakerPlugin from svn.TiddlyWiki.org repository]]
[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/TiddlerTweakerPlugin.js]]
[[window.story.displayTiddler(null,'TiddlerTweaker')]]
[[version.extensions.TiddlerTweakerPlugin!=undefined]]
>>
*<<tiddler LoadRemotePlugin with:
[[ImportTiddlersPlugin]]
[[Load ImportTiddlersPlugin from svn.TiddlyWiki.org repository]]
[[http://svn.tiddlywiki.org/Trunk/contributors/EricShulman/plugins/ImportTiddlersPlugin.js]]
[[window.story.displayTiddler(null,"ImportTiddlers")]]
[[version.extensions.ImportTiddlersPlugin!=undefined]]
[[window.story.displayTiddler(null,"ImportTiddlers")]]
[[zRemotePluginsConfig]]
>>
*<<tiddler LoadRemotePlugin with:
[[Firefox Privileges]]
[[Load Firefox Privilege Manager from svn.TiddlyWiki.org repository]]
[[http://svn.tiddlywiki.org/Trunk/contributors/XavierVerges/plugins/FirefoxPrivilegesPlugin.js]]
[[config.macros.firefoxPrivileges.onload()]]
[[config.macros.firefoxPrivileges!=undefined]]
[[backstage.switchTab("firefoxPrivileges")]]
>>
//customize://
<<tiddler listTiddlersByTag with: customize "" String()>>//macros://
*<<saveStory>>
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|2.0.0|
|License|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.displayTiddler,TiddlyWiki.prototype.deleteTiddler|
|Options|##Configuration|
|Description|list/jump to tiddlers viewed during this session plus "back" button/macro|
This plugin provides a list of links to all tiddlers opened during the session, creating a "trail of breadcrumbs" from one tiddler to the next, allowing you to quickly navigate to any previously viewed tiddler, or select 'home' to reset the display to the initial set of tiddlers that were open at the start of the session (i.e., when the document was loaded into the browser).
!!!!!Documentation
<<<
see [[BreadcrumbsPluginInfo]]
<<<
!!!!!Configuration
<<<
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
<<option chkBreadcrumbsHideHomeLink>> omit 'Home' link from breadcrumbs display
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<option chkBreadcrumbsReverse>> show breadcrumbs in reverse order (most recent first)
<<option chkBreadcrumbsLimit>> limit breadcrumbs display to {{twochar{<<option txtBreadcrumbsLimit>>}}} items
<<option chkBreadcrumbsLimitOpenTiddlers>> limit open tiddlers to {{twochar{<<option txtBreadcrumbsLimitOpenTiddlers>>}}} items
<<<
!!!!!Revisions
<<<
2008.05.01 [2.0.0] added 'limit open tiddlers' feature (with safety check for tiddler in edit mode)
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.breadCrumbs = {major: 2, minor: 0, revision: 0, date: new Date("May 1, 2008")};
var co=config.options; // abbreviation
// show/hide display option (default is to SHOW breadcrumbs)
if (co.chkShowBreadcrumbs===undefined) co.chkShowBreadcrumbs=true;
// REORDER breadcrumbs when visiting previously viewed tiddler (default)
if (co.chkReorderBreadcrumbs===undefined) co.chkReorderBreadcrumbs=true;
// create default breadcrumbs display as needed (default is to CREATE)
if (co.chkCreateDefaultBreadcrumbs===undefined) co.chkCreateDefaultBreadcrumbs=true;
// show breadcrumbs for 'startup' tiddlers (default is FALSE = only show crumbs for tiddlers opened after startup)
if (co.chkShowStartupBreadcrumbs===undefined) co.chkShowStartupBreadcrumbs=false;
// show crumbs in reverse order (most recent first)
if (co.chkBreadcrumbsReverse===undefined) co.chkBreadcrumbsReverse=false;
// limit number of crumbs displayed
if (co.chkBreadcrumbsLimit===undefined) co.chkBreadcrumbsLimit=false;
if (co.txtBreadcrumbsLimit===undefined) co.txtBreadcrumbsLimit=5;
// limit number of open tiddlers
if (co.chkBreadcrumbsLimitOpenTiddlers===undefined) co.chkBreadcrumbsLimitOpenTiddlers=false;
if (co.txtBreadcrumbsLimitOpenTiddlers===undefined) co.txtBreadcrumbsLimitOpenTiddlers=3;
// omit home link from breadcrumbs display
if (co.chkBreadcrumbsHideHomeLink===undefined) co.chkBreadcrumbsHideHomeLink=false;
config.macros.breadcrumbs = {
crumbs: [], // the list of current breadcrumbs
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var area=createTiddlyElement(place,"span",null,"breadCrumbs",null);
area.setAttribute("homeSep",params[0]?params[0]:this.homeSeparator); // custom home separator
area.setAttribute("crumbSep",params[1]?params[1]:this.crumbSeparator); // custom crumb separator
this.render(area);
},
add: function (title) {
var thisCrumb = title;
var ind = this.crumbs.indexOf(thisCrumb);
if(ind === -1)
this.crumbs.push(thisCrumb);
else if (config.options.chkReorderBreadcrumbs)
this.crumbs.push(this.crumbs.splice(ind,1)[0]); // reorder crumbs
else
this.crumbs=this.crumbs.slice(0,ind+1); // trim crumbs
if (config.options.chkBreadcrumbsLimitOpenTiddlers)
this.limitOpenTiddlers();
this.refresh();
return false;
},
getAreas: function() {
var crumbAreas=[];
// find all DIVs with classname=="breadCrumbs"
// Note: use try/catch to avoid "Bad NPObject as private data" fatal error caused when
// some versions of embedded QuickTime player element is accessed by hasClass() function.
var all=document.getElementsByTagName("*");
for (var i=0; i<all.length; i++)
try{ if (hasClass(all[i],"breadCrumbs")) crumbAreas.push(all[i]); } catch(e) {;}
// find single DIV w/fixed ID (backward compatibility)
var byID=document.getElementById("breadCrumbs")
if (byID && !hasClass(byID,"breadCrumbs")) crumbAreas.push(byID);
if (!crumbAreas.length && config.options.chkCreateDefaultBreadcrumbs) {
// no existing crumbs display areas... create one...
var defaultArea = createTiddlyElement(null,"span",null,"breadCrumbs",null);
defaultArea.style.display= "none";
var targetArea= document.getElementById("tiddlerDisplay");
targetArea.parentNode.insertBefore(defaultArea,targetArea);
crumbAreas.push(defaultArea);
}
return crumbAreas;
},
refresh: function() {
var crumbAreas=this.getAreas();
for (var i=0; i<crumbAreas.length; i++) {
crumbAreas[i].style.display = config.options.chkShowBreadcrumbs?"block":"none";
removeChildren(crumbAreas[i]);
this.render(crumbAreas[i]);
}
},
render: function(here) {
var out=""
var homeSep=here.getAttribute("homeSep"); if (!homeSep) homeSep=this.homeSeparator;
var crumbSep=here.getAttribute("crumbSep"); if (!crumbSep) crumbSep=this.crumbSeparator;
if (!config.options.chkBreadcrumbsHideHomeLink) {
createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
out+=homeSep;
}
for (c=0; c<this.crumbs.length; c++) // remove non-existing tiddlers from crumbs
if (!store.tiddlerExists(this.crumbs[c]) && !store.isShadowTiddler(this.crumbs[c]))
this.crumbs.splice(c,1);
var count=this.crumbs.length;
if (config.options.chkBreadcrumbsLimit && config.options.txtBreadcrumbsLimit<count)
count=config.options.txtBreadcrumbsLimit;
var list=[];
for (c=this.crumbs.length-count; c<this.crumbs.length; c++) list.push('[['+this.crumbs[c]+']]');
if (config.options.chkBreadcrumbsReverse) list.reverse();
out+=list.join(crumbSep);
wikify(out,here);
},
home: function() {
story.closeAllTiddlers();
restart();
config.macros.breadcrumbs.crumbs = [];
var crumbAreas=config.macros.breadcrumbs.getAreas();
for (var i=0; i<crumbAreas.length; i++) crumbAreas[i].style.display = "none";
return false;
},
limitOpenTiddlers: function() {
var limit=config.options.txtBreadcrumbsLimitOpenTiddlers; if (limit<1) limit=1;
for (c=this.crumbs.length-1; c>=0; c--) {
var tid=this.crumbs[c];
var elem=document.getElementById(story.idPrefix+tid);
if (elem) { // tiddler is displayed
if (limit <=0) { // display limit has been reached
if (elem.getAttribute("dirty")=="true") { // tiddler is being edited
var msg="'"+tid+"' is currently being edited.\n\n";
msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
if (confirm(msg)) { story.saveTiddler(tid); story.closeTiddler(tid); }
}
else
story.closeTiddler(this.crumbs[c]);
}
limit--;
}
}
}
};
if (config.macros.breadcrumbs.homeSeparator==undefined) // note: not a cookie
config.macros.breadcrumbs.homeSeparator=" | ";
if (config.macros.breadcrumbs.crumbSeparator==undefined) // note: not a cookie
config.macros.breadcrumbs.crumbSeparator=" > ";
config.commands.previousTiddler = {
text: 'back',
tooltip: 'view the previous tiddler',
hideReadOnly: false,
dateFormat: 'DDD, MMM DDth YYYY hh:0mm:0ss',
handler: function(event,src,title) {
var here=story.findContainingTiddler(src); if (!here) return;
var crumbs=config.macros.breadcrumbs.crumbs;
if (crumbs.length>1) {
var crumb=crumbs[crumbs.length-2];
story.displayTiddler(here,crumb);
}
else
config.macros.breadcrumbs.home();
return false;
}
};
config.macros.previousTiddler= {
label: 'back',
prompt: 'view the previous tiddler',
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var label=params.shift(); if (!label) label=this.label;
var prompt=params.shift(); if (!prompt) prompt=this.prompt;
createTiddlyButton(place,label,prompt,function() {
var crumbs=config.macros.breadcrumbs.crumbs;
if (crumbs.length>1) {
var crumb=crumbs[crumbs.length-2];
story.displayTiddler(place,crumb);
}
else
config.macros.breadcrumbs.home();
});
}
}
// hijack story.displayTiddler() so crumbs can be refreshed when a tiddler is displayed
if (Story.prototype.breadCrumbs_coreDisplayTiddler==undefined)
Story.prototype.breadCrumbs_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
this.breadCrumbs_coreDisplayTiddler.apply(this,arguments);
// if not displaying tiddler during document startup, then add it to the breadcrumbs
// note: 'startingUp' flag is a global, set/reset by the core init() function
if (!startingUp || config.options.chkShowStartupBreadcrumbs) config.macros.breadcrumbs.add(title);
}
// hijack store.removeTiddler() so crumbs can be refreshed when a tiddler is deleted
if (TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler==undefined)
TiddlyWiki.prototype.breadCrumbs_coreRemoveTiddler=TiddlyWiki.prototype.removeTiddler;
TiddlyWiki.prototype.removeTiddler= function(title)
{
this.breadCrumbs_coreRemoveTiddler.apply(this,arguments);
config.macros.breadcrumbs.refresh();
}
//}}}
/***
|Name|CalendarPlugin|
|Source|http://www.TiddlyTools.com/#CalendarPlugin|
|Version|2008.09.09|
|Author|Eric Shulman|
|Original Author|SteveRumsby|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|display monthly and yearly calendars|
NOTE: For enhanced date display (including popups), you must also install [[DatePlugin]]
!!!!!Usage:
<<<
|{{{<<calendar>>}}}|Produce a full-year calendar for the current year|
|{{{<<calendar year>>}}}|Produce a full-year calendar for the given year|
|{{{<<calendar year month>>}}}|Produce a one-month calendar for the given month and year|
|{{{<<calendar thismonth>>}}}|Produce a one-month calendar for the current month|
|{{{<<calendar lastmonth>>}}}|Produce a one-month calendar for last month|
|{{{<<calendar nextmonth>>}}}|Produce a one-month calendar for next month|
|{{{<<calendar +n>>}}}<br>{{{<<calendar -n>>}}}|Produce a one-month calendar for a month +/- 'n' months from now|
<<<
!!!!!Configuration:
<<<
|''First day of week:''<br>{{{config.options.txtCalFirstDay}}}|<<option txtCalFirstDay>>|(Monday = 0, Sunday = 6)|
|''First day of weekend:''<br>{{{config.options.txtCalStartOfWeekend}}}|<<option txtCalStartOfWeekend>>|(Monday = 0, Sunday = 6)|
<<option chkDisplayWeekNumbers>> Display week numbers //(note: Monday will be used as the start of the week)//
|''Week number display format:''<br>{{{config.options.txtWeekNumberDisplayFormat }}}|<<option txtWeekNumberDisplayFormat >>|
|''Week number link format:''<br>{{{config.options.txtWeekNumberLinkFormat }}}|<<option txtWeekNumberLinkFormat >>|
<<<
!!!!!Revisions
<<<
2008.09.10: added "+n" (and "-n") param to permit display of relative months (e.g., "+6" means "six months from now", "-3" means "three months ago". Based on suggestion from Jean.
2008.06.17: added support for config.macros.calendar.todaybg
2008.02.27: in handler(), DON'T set hard-coded default date format, so that *customized* value (pre-defined in config.macros.calendar.journalDateFmt is used.
2008.02.17: in createCalendarYear(), fix next/previous year calculation (use parseInt() to convert to numeric value). Also, use journalDateFmt for date linking when NOT using [[DatePlugin]].
2008.02.16: in createCalendarDay(), week numbers now created as TiddlyLinks, allowing quick creation/navigation to 'weekly' journals (based on request from Kashgarinn)
2008.01.08: in createCalendarMonthHeader(), "month year" heading is now created as TiddlyLink, allowing quick creation/navigation to 'month-at-a-time' journals
2007.11.30: added "return false" to onclick handlers (prevent IE from opening blank pages)
2006.08.23: added handling for weeknumbers (code supplied by Martin Budden (see "wn**" comment marks). Also, incorporated updated by Jeremy Sheeley to add caching for reminders (see [[ReminderMacros]], if installed)
2005.10.30: in config.macros.calendar.handler(), use "tbody" element for IE compatibility. Also, fix year calculation for IE's getYear() function (which returns '2005' instead of '105'). Also, in createCalendarDays(), use showDate() function (see [[DatePlugin]], if installed) to render autostyled date with linked popup. Updated calendar stylesheet definition: use .calendar class-specific selectors, add text centering and margin settings
2006.05.29: added journalDateFmt handling
<<<
***/
/***
!!!!!Code section:
***/
//{{{
version.extensions.calendar = { major: 0, minor: 7, revision: 0, date: new Date(2008, 6, 17)};
if(config.options.txtCalFirstDay == undefined)
config.options.txtCalFirstDay = 0;
if(config.options.txtCalStartOfWeekend == undefined)
config.options.txtCalStartOfWeekend = 5;
if(config.options.chkDisplayWeekNumbers == undefined)//wn**
config.options.chkDisplayWeekNumbers = false;
if(config.options.chkDisplayWeekNumbers)
config.options.txtCalFirstDay = 0;
if(config.options.txtWeekNumberDisplayFormat == undefined)//wn**
config.options.txtWeekNumberDisplayFormat = "w0WW";
if(config.options.txtWeekNumberLinkFormat == undefined)//wn**
config.options.txtWeekNumberLinkFormat = "YYYY-w0WW";
config.macros.calendar = {};
config.macros.calendar.monthnames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
config.macros.calendar.daynames = ["M", "T", "W", "T", "F", "S", "S"];
config.macros.calendar.todaybg = "#ccccff";
config.macros.calendar.weekendbg = "#c0c0c0";
config.macros.calendar.monthbg = "#e0e0e0";
config.macros.calendar.holidaybg = "#ffc0c0";
config.macros.calendar.journalDateFmt = "DD MMM YYYY";
config.macros.calendar.monthdays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
config.macros.calendar.holidays = [ ]; // Not sure this is required anymore - use reminders instead
//}}}
//{{{
function calendarIsHoliday(date) // Is the given date a holiday?
{
var longHoliday = date.formatString("0DD/0MM/YYYY");
var shortHoliday = date.formatString("0DD/0MM");
for(var i = 0; i < config.macros.calendar.holidays.length; i++) {
if(config.macros.calendar.holidays[i] == longHoliday || config.macros.calendar.holidays[i] == shortHoliday)
return true;
}
return false;
}
//}}}
//{{{
config.macros.calendar.handler = function(place,macroName,params) {
var calendar = createTiddlyElement(place, "table", null, "calendar", null);
var tbody = createTiddlyElement(calendar, "tbody", null, null, null);
var today = new Date();
var year = today.getYear();
if (year<1900) year+=1900;
// get format for journal link by reading from SideBarOptions (ELS 5/29/06 - based on suggestion by Martin Budden)
var text = store.getTiddlerText("SideBarOptions");
var re = new RegExp("<<(?:newJournal)([^>]*)>>","mg"); var fm = re.exec(text);
if (fm && fm[1]!=null) { var pa=fm[1].readMacroParams(); if (pa[0]) this.journalDateFmt = pa[0]; }
var month=-1;
if (params[0] == "thismonth") {
var month=today.getMonth();
} else if (params[0] == "lastmonth") {
var month = today.getMonth()-1; if (month==-1) { month=11; year--; }
} else if (params[0] == "nextmonth") {
var month = today.getMonth()+1; if (month>11) { month=0; year++; }
} else if (params[0]&&"+-".indexOf(params[0].substr(0,1))!=-1) {
var month = today.getMonth()+parseInt(params[0]);
if (month>11) { year+=Math.floor(month/12); month%=12; };
if (month<0) { year+=Math.floor(month/12); month=12+month%12; }
} else if (params[0]) {
year = params[0];
if(params[1]) month=parseInt(params[1])-1;
if (month>11) month=11; if (month<0) month=0;
}
if (month!=-1) {
cacheReminders(new Date(year, month, 1, 0, 0), 31);
createCalendarOneMonth(tbody, year, month);
} else {
cacheReminders(new Date(year, 0, 1, 0, 0), 366);
createCalendarYear(tbody, year);
}
window.reminderCacheForCalendar = null;
}
//}}}
//{{{
//This global variable is used to store reminders that have been cached
//while the calendar is being rendered. It will be renulled after the calendar is fully rendered.
window.reminderCacheForCalendar = null;
//}}}
//{{{
function cacheReminders(date, leadtime)
{
if (window.findTiddlersWithReminders == null) return;
window.reminderCacheForCalendar = {};
var leadtimeHash = [];
leadtimeHash [0] = 0;
leadtimeHash [1] = leadtime;
var t = findTiddlersWithReminders(date, leadtimeHash, null, 1);
for(var i = 0; i < t.length; i++) {
//just tag it in the cache, so that when we're drawing days, we can bold this one.
window.reminderCacheForCalendar[t[i]["matchedDate"]] = "reminder:" + t[i]["params"]["title"];
}
}
//}}}
//{{{
function createCalendarOneMonth(calendar, year, mon)
{
var row = createTiddlyElement(calendar, "tr", null, null, null);
createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, true, year, mon);
row = createTiddlyElement(calendar, "tr", null, null, null);
createCalendarDayHeader(row, 1);
createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarMonth(calendar, year, mon)
{
var row = createTiddlyElement(calendar, "tr", null, null, null);
createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon] + " " + year, false, year, mon);
row = createTiddlyElement(calendar, "tr", null, null, null);
createCalendarDayHeader(row, 1);
createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarYear(calendar, year)
{
var row;
row = createTiddlyElement(calendar, "tr", null, null, null);
var back = createTiddlyElement(row, "td", null, null, null);
var backHandler = function() {
removeChildren(calendar);
createCalendarYear(calendar, parseInt(year)-1);
return false; // consume click
};
createTiddlyButton(back, "<", "Previous year", backHandler);
back.align = "center";
var yearHeader = createTiddlyElement(row, "td", null, "calendarYear", year);
yearHeader.align = "center";
yearHeader.setAttribute("colSpan",config.options.chkDisplayWeekNumbers?22:19);//wn**
var fwd = createTiddlyElement(row, "td", null, null, null);
var fwdHandler = function() {
removeChildren(calendar);
createCalendarYear(calendar, parseInt(year)+1);
return false; // consume click
};
createTiddlyButton(fwd, ">", "Next year", fwdHandler);
fwd.align = "center";
createCalendarMonthRow(calendar, year, 0);
createCalendarMonthRow(calendar, year, 3);
createCalendarMonthRow(calendar, year, 6);
createCalendarMonthRow(calendar, year, 9);
}
//}}}
//{{{
function createCalendarMonthRow(cal, year, mon)
{
var row = createTiddlyElement(cal, "tr", null, null, null);
createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon], false, year, mon);
createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+1], false, year, mon);
createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+2], false, year, mon);
row = createTiddlyElement(cal, "tr", null, null, null);
createCalendarDayHeader(row, 3);
createCalendarDayRows(cal, year, mon);
}
//}}}
//{{{
function createCalendarMonthHeader(cal, row, name, nav, year, mon)
{
var month;
if (nav) {
var back = createTiddlyElement(row, "td", null, null, null);
back.align = "center";
back.style.background = config.macros.calendar.monthbg;
var backMonHandler = function() {
var newyear = year;
var newmon = mon-1;
if(newmon == -1) { newmon = 11; newyear = newyear-1;}
removeChildren(cal);
cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
createCalendarOneMonth(cal, newyear, newmon);
return false; // consume click
};
createTiddlyButton(back, "<", "Previous month", backMonHandler);
month = createTiddlyElement(row, "td", null, "calendarMonthname")
createTiddlyLink(month,name,true);
month.setAttribute("colSpan", config.options.chkDisplayWeekNumbers?6:5);//wn**
var fwd = createTiddlyElement(row, "td", null, null, null);
fwd.align = "center";
fwd.style.background = config.macros.calendar.monthbg;
var fwdMonHandler = function() {
var newyear = year;
var newmon = mon+1;
if(newmon == 12) { newmon = 0; newyear = newyear+1;}
removeChildren(cal);
cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
createCalendarOneMonth(cal, newyear, newmon);
return false; // consume click
};
createTiddlyButton(fwd, ">", "Next month", fwdMonHandler);
} else {
month = createTiddlyElement(row, "td", null, "calendarMonthname", name)
month.setAttribute("colSpan",config.options.chkDisplayWeekNumbers?8:7);//wn**
}
month.align = "center";
month.style.background = config.macros.calendar.monthbg;
}
//}}}
//{{{
function createCalendarDayHeader(row, num)
{
var cell;
for(var i = 0; i < num; i++) {
if (config.options.chkDisplayWeekNumbers) createTiddlyElement(row, "td");//wn**
for(var j = 0; j < 7; j++) {
var d = j + (config.options.txtCalFirstDay - 0);
if(d > 6) d = d - 7;
cell = createTiddlyElement(row, "td", null, null, config.macros.calendar.daynames[d]);
if(d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))
cell.style.background = config.macros.calendar.weekendbg;
}
}
}
//}}}
//{{{
function createCalendarDays(row, col, first, max, year, mon) {
var i;
if (config.options.chkDisplayWeekNumbers){
if (first<=max) {
var ww = new Date(year,mon,first);
var td=createTiddlyElement(row, "td");//wn**
var link=createTiddlyLink(td,ww.formatString(config.options.txtWeekNumberLinkFormat),false);
link.appendChild(document.createTextNode(ww.formatString(config.options.txtWeekNumberDisplayFormat)));
}
else createTiddlyElement(row, "td", null, null, null);//wn**
}
for(i = 0; i < col; i++)
createTiddlyElement(row, "td", null, null, null);
var day = first;
for(i = col; i < 7; i++) {
var d = i + (config.options.txtCalFirstDay - 0);
if(d > 6) d = d - 7;
var daycell = createTiddlyElement(row, "td", null, null, null);
var isaWeekend = ((d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))? true:false);
if(day > 0 && day <= max) {
var celldate = new Date(year, mon, day);
// ELS 2005.10.30: use <<date>> macro's showDate() function to create popup
// ELS 5/29/06 - use journalDateFmt
if (window.showDate)
showDate(daycell,celldate,"popup","DD",config.macros.calendar.journalDateFmt,true, isaWeekend);
else {
if(isaWeekend) daycell.style.background = config.macros.calendar.weekendbg;
var title = celldate.formatString(config.macros.calendar.journalDateFmt);
if(calendarIsHoliday(celldate))
daycell.style.background = config.macros.calendar.holidaybg;
var now=new Date();
if ((now-celldate>=0) && (now-celldate<86400000)) // is today?
daycell.style.background = config.macros.calendar.todaybg;
if(window.findTiddlersWithReminders == null) {
var link = createTiddlyLink(daycell, title, false);
link.appendChild(document.createTextNode(day));
} else
var button = createTiddlyButton(daycell, day, title, onClickCalendarDate);
}
}
day++;
}
}
//}}}
//{{{
// We've clicked on a day in a calendar - create a suitable pop-up of options.
// The pop-up should contain:
// * a link to create a new entry for that date
// * a link to create a new reminder for that date
// * an <hr>
// * the list of reminders for that date
// NOTE: The following code is only used when [[DatePlugin]] is not present
function onClickCalendarDate(e)
{
var button = this;
var date = button.getAttribute("title");
var dat = new Date(date.substr(6,4), date.substr(3,2)-1, date.substr(0, 2));
date = dat.formatString(config.macros.calendar.journalDateFmt);
var popup = createTiddlerPopup(this);
popup.appendChild(document.createTextNode(date));
var newReminder = function() {
var t = store.getTiddlers(date);
displayTiddler(null, date, 2, null, null, false, false);
if(t) {
document.getElementById("editorBody" + date).value += "\n<<reminder day:" + dat.getDate() +
" month:" + (dat.getMonth()+1) + " year:" + (dat.getYear()+1900) + " title: >>";
} else {
document.getElementById("editorBody" + date).value = "<<reminder day:" + dat.getDate() +
" month:" + (dat.getMonth()+1) +" year:" + (dat.getYear()+1900) + " title: >>";
}
return false; // consume click
};
var link = createTiddlyButton(popup, "New reminder", null, newReminder);
popup.appendChild(document.createElement("hr"));
var t = findTiddlersWithReminders(dat, [0,14], null, 1);
for(var i = 0; i < t.length; i++) {
link = createTiddlyLink(popup, t[i].tiddler, false);
link.appendChild(document.createTextNode(t[i].tiddler));
}
return false; // consume click
}
//}}}
//{{{
function calendarMaxDays(year, mon)
{
var max = config.macros.calendar.monthdays[mon];
if(mon == 1 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) max++;
return max;
}
//}}}
//{{{
function createCalendarDayRows(cal, year, mon)
{
var row = createTiddlyElement(cal, "tr", null, null, null);
var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first1 < 0) first1 = first1 + 7;
var day1 = -first1 + 1;
var first2 = (new Date(year, mon+1, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first2 < 0) first2 = first2 + 7;
var day2 = -first2 + 1;
var first3 = (new Date(year, mon+2, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first3 < 0) first3 = first3 + 7;
var day3 = -first3 + 1;
var max1 = calendarMaxDays(year, mon);
var max2 = calendarMaxDays(year, mon+1);
var max3 = calendarMaxDays(year, mon+2);
while(day1 <= max1 || day2 <= max2 || day3 <= max3) {
row = createTiddlyElement(cal, "tr", null, null, null);
createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
createCalendarDays(row, 0, day2, max2, year, mon+1); day2 += 7;
createCalendarDays(row, 0, day3, max3, year, mon+2); day3 += 7;
}
}
//}}}
//{{{
function createCalendarDayRowsSingle(cal, year, mon)
{
var row = createTiddlyElement(cal, "tr", null, null, null);
var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first1 < 0) first1 = first1+ 7;
var day1 = -first1 + 1;
var max1 = calendarMaxDays(year, mon);
while(day1 <= max1) {
row = createTiddlyElement(cal, "tr", null, null, null);
createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
}
}
//}}}
//{{{
setStylesheet(".calendar, .calendar table, .calendar th, .calendar tr, .calendar td { text-align:center; } .calendar, .calendar a { margin:0px !important; padding:0px !important; }", "calendarStyles");
//}}}
// // override cookie settings for CalendarPlugin:
//{{{
config.options.txtCalFirstDay=6;
config.options.txtCalStartOfWeekend=5;
//}}}
// // override internal default settings for CalendarPlugin:
//{{{
config.macros.calendar.journalDateFmt="DDD MMM 0DD YYYY";
//}}}
/***
|Name|CheckboxPlugin|
|Source|http://www.TiddlyTools.com/#CheckboxPlugin|
|Documentation|http://www.TiddlyTools.com/#CheckboxPluginInfo|
|Version|2.4.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Add checkboxes to your tiddler content|
This plugin extends the TiddlyWiki syntax to allow definition of checkboxes that can be embedded directly in tiddler content. Checkbox states are preserved by:
* by setting/removing tags on specified tiddlers,
* or, by setting custom field values on specified tiddlers,
* or, by saving to a locally-stored cookie ID,
* or, automatically modifying the tiddler content (deprecated)
When an ID is assigned to the checkbox, it enables direct programmatic access to the checkbox DOM element, as well as creating an entry in TiddlyWiki's config.options[ID] internal data. In addition to tracking the checkbox state, you can also specify custom javascript for programmatic initialization and onClick event handling for any checkbox, so you can provide specialized side-effects in response to state changes.
!!!!!Documentation
>see [[CheckboxPluginInfo]]
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to [[CheckboxPluginInfo]]
2008.01.05 [2.4.0] set global "window.place" to current checkbox element when processing checkbox clicks. This allows init/beforeClick/afterClick handlers to reference RELATIVE elements, including using "story.findContainingTiddler(place)". Also, wrap handlers in "function()" so "return" can be used within handler code.
|please see [[CheckboxPluginInfo]] for additional revision details|
2005.12.07 [0.9.0] initial BETA release
<<<
!!!!!Code
***/
//{{{
version.extensions.CheckboxPlugin = {major: 2, minor: 4, revision:0 , date: new Date(2008,1,5)};
//}}}
//{{{
config.checkbox = { refresh: { tagged:true, tagging:true, container:true } };
config.formatters.push( {
name: "checkbox",
match: "\\[[xX_ ][\\]\\=\\(\\{]",
lookahead: "\\[([xX_ ])(=[^\\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) {
// get params
var checked=(lookaheadMatch[1].toUpperCase()=="X");
var id=lookaheadMatch[2];
var target=lookaheadMatch[3];
if (target) target=target.substr(1,target.length-2).trim(); // trim off parentheses
var fn_init=lookaheadMatch[4];
var fn_clickBefore=lookaheadMatch[5];
var fn_clickAfter=lookaheadMatch[6];
var tid=story.findContainingTiddler(w.output); if (tid) tid=tid.getAttribute("tiddler");
var srctid=w.tiddler?w.tiddler.title:null;
config.macros.checkbox.create(w.output,tid,srctid,w.matchStart+1,checked,id,target,config.checkbox.refresh,fn_init,fn_clickBefore,fn_clickAfter);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
} );
config.macros.checkbox = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
if(!(tiddler instanceof Tiddler)) { // if no tiddler passed in try to find one
var here=story.findContainingTiddler(place);
if (here) tiddler=store.getTiddler(here.getAttribute("tiddler"))
}
var srcpos=0; // "inline X" not applicable to macro syntax
var target=params.shift(); if (!target) target="";
var defaultState=params[0]=="checked"; if (defaultState) params.shift();
var id=params.shift(); if (id && !id.length) id=null;
var fn_init=params.shift(); if (fn_init && !fn_init.length) fn_init=null;
var fn_clickBefore=params.shift();
if (fn_clickBefore && !fn_clickBefore.length) fn_clickBefore=null;
var fn_clickAfter=params.shift();
if (fn_clickAfter && !fn_clickAfter.length) fn_clickAfter=null;
var refresh={ tagged:true, tagging:true, container:false };
this.create(place,tiddler.title,tiddler.title,0,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter);
},
create: function(place,tid,srctid,srcpos,defaultState,id,target,refresh,fn_init,fn_clickBefore,fn_clickAfter) {
// create checkbox element
var c = document.createElement("input");
c.setAttribute("type","checkbox");
c.onclick=this.onClickCheckbox;
c.srctid=srctid; // remember source tiddler
c.srcpos=srcpos; // remember location of "X"
c.container=tid; // containing tiddler (may be null if not in a tiddler)
c.tiddler=tid; // default target tiddler
c.refresh = {};
c.refresh.container = refresh.container;
c.refresh.tagged = refresh.tagged;
c.refresh.tagging = refresh.tagging;
place.appendChild(c);
// set default state
c.checked=defaultState;
// track state in config.options.ID
if (id) {
c.id=id.substr(1); // trim off leading "="
if (config.options[c.id]!=undefined)
c.checked=config.options[c.id];
else
config.options[c.id]=c.checked;
}
// track state in (tiddlername|tagname) or (fieldname@tiddlername)
if (target) {
var pos=target.indexOf("@");
if (pos!=-1) {
c.field=pos?target.substr(0,pos):"checked"; // get fieldname (or use default "checked")
c.tiddler=target.substr(pos+1); // get specified tiddler name (if any)
if (!c.tiddler || !c.tiddler.length) c.tiddler=tid; // if tiddler not specified, default == container
if (store.getValue(c.tiddler,c.field)!=undefined)
c.checked=(store.getValue(c.tiddler,c.field)=="true"); // set checkbox from saved state
} else {
var pos=target.indexOf("|"); if (pos==-1) var pos=target.indexOf(":");
c.tag=target;
if (pos==0) c.tag=target.substr(1); // trim leading "|" or ":"
if (pos>0) { c.tiddler=target.substr(0,pos); c.tag=target.substr(pos+1); }
if (!c.tag.length) c.tag="checked";
var t=store.getTiddler(c.tiddler);
if (t && t.tags)
c.checked=t.isTagged(c.tag); // set checkbox from saved state
}
}
// trim off surrounding { and } delimiters from init/click handlers
if (fn_init) c.fn_init="(function(){"+fn_init.trim().substr(1,fn_init.length-2)+"})()";
if (fn_clickBefore) c.fn_clickBefore="(function(){"+fn_clickBefore.trim().substr(1,fn_clickBefore.length-2)+"})()";
if (fn_clickAfter) c.fn_clickAfter="(function(){"+fn_clickAfter.trim().substr(1,fn_clickAfter.length-2)+"})()";
c.init=true; c.onclick(); c.init=false; // compute initial state and save in tiddler/config/cookie
},
onClickCheckbox: function(event) {
window.place=this;
if (this.init && this.fn_init) // custom function hook to set initial state (run only once)
{ try { eval(this.fn_init); } catch(e) { displayMessage("Checkbox init error: "+e.toString()); } }
if (!this.init && this.fn_clickBefore) // custom function hook to override changes in checkbox state
{ try { eval(this.fn_clickBefore) } catch(e) { displayMessage("Checkbox onClickBefore error: "+e.toString()); } }
if (this.id)
// save state in config AND cookie (only when ID starts with 'chk')
{ config.options[this.id]=this.checked; if (this.id.substr(0,3)=="chk") saveOptionCookie(this.id); }
if (this.srctid && this.srcpos>0 && (!this.id || this.id.substr(0,3)!="chk") && !this.tag && !this.field) {
// save state in tiddler content only if not using cookie, tag or field tracking
var t=store.getTiddler(this.srctid); // put X in original source tiddler (if any)
if (t && this.checked!=(t.text.substr(this.srcpos,1).toUpperCase()=="X")) { // if changed
t.set(null,t.text.substr(0,this.srcpos)+(this.checked?"X":"_")+t.text.substr(this.srcpos+1),null,null,t.tags);
if (!story.isDirty(t.title)) story.refreshTiddler(t.title,null,true);
store.setDirty(true);
}
}
if (this.field) {
if (this.checked && !store.tiddlerExists(this.tiddler))
store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
// set the field value in the target tiddler
store.setValue(this.tiddler,this.field,this.checked?"true":"false");
// DEBUG: displayMessage(this.field+"@"+this.tiddler+" is "+this.checked);
}
if (this.tag) {
if (this.checked && !store.tiddlerExists(this.tiddler))
store.saveTiddler(this.tiddler,this.tiddler,"",config.options.txtUserName,new Date());
var t=store.getTiddler(this.tiddler);
if (t) {
var tagged=(t.tags && t.tags.indexOf(this.tag)!=-1);
if (this.checked && !tagged) { t.tags.push(this.tag); store.setDirty(true); }
if (!this.checked && tagged) { t.tags.splice(t.tags.indexOf(this.tag),1); store.setDirty(true); }
}
// if tag state has been changed, update display of corresponding tiddlers (unless they are in edit mode...)
if (this.checked!=tagged) {
if (this.refresh.tagged) {
if (!story.isDirty(this.tiddler)) // the TAGGED tiddler in view mode
story.refreshTiddler(this.tiddler,null,true);
else // the TAGGED tiddler in edit mode (with tags field)
config.macros.checkbox.refreshEditorTagField(this.tiddler,this.tag,this.checked);
}
if (this.refresh.tagging)
if (!story.isDirty(this.tag)) story.refreshTiddler(this.tag,null,true); // the TAGGING tiddler
}
}
if (!this.init && this.fn_clickAfter) // custom function hook to react to changes in checkbox state
{ try { eval(this.fn_clickAfter) } catch(e) { displayMessage("Checkbox onClickAfter error: "+e.toString()); } }
// refresh containing tiddler (but not during initial rendering, or we get an infinite loop!) (and not when editing container)
if (!this.init && this.refresh.container && this.container!=this.tiddler)
if (!story.isDirty(this.container)) story.refreshTiddler(this.container,null,true); // the tiddler CONTAINING the checkbox
return true;
},
refreshEditorTagField: function(title,tag,set) {
var tagfield=story.getTiddlerField(title,"tags");
if (!tagfield||tagfield.getAttribute("edit")!="tags") return; // if no tags field in editor (i.e., custom template)
var tags=tagfield.value.readBracketedList();
if (tags.contains(tag)==set) return; // if no change needed
if (set) tags.push(tag); // add tag
else tags.splice(tags.indexOf(tag),1); // remove tag
for (var t=0;t<tags.length;t++) tags[t]=String.encodeTiddlyLink(tags[t]);
tagfield.value=tags.join(" "); // reassemble tag string (with brackets as needed)
return;
}
}
//}}}
/***
|Name:|CloseOnCancelPlugin|
|Description:|Closes the tiddler if you click new tiddler then cancel. Default behaviour is to leave it open|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#CloseOnCancelPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.commands.cancelTiddler,{
handler_mptw_orig_closeUnsaved: config.commands.cancelTiddler.handler,
handler: function(event,src,title) {
this.handler_mptw_orig_closeUnsaved(event,src,title);
if (!store.tiddlerExists(title) && !store.isShadowTiddler(title))
story.closeTiddler(title,true);
return false;
}
});
//}}}
/***
|Name|CollapseTiddlersPlugin|
|Source|http://gensoft.revhost.net/Collapse.html|
|Version|2008.03.06|
|Author|Bradley Meck (modified by ELS)|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CollapsedTemplate|
|Overrides||
|Description|show/hide content of a tiddler while leaving tiddler title visible|
|ELS 3/6/2008: refactored code for size reduction, readability, and I18N/L10N-readiness. Also added 'folded' flag to tiddler elements (for use by other plugins that need to know if tiddler is folded (e.g., [[SinglePageModePlugin]]) |
|ELS 10/11/2007: moved [[FoldFirst]] inline script and converted to {{{<<foldFirst>>}}} macro. |
|ELS 9/12/2007: suspend/resume SinglePageMode (SPM/TPM/BPM) when folding/unfolding tiddlers |
|ELS 6/5/2007: add "return false" at the end of each command handler to prevent IE 'page transition' problem. |
|ELS 3/30/2007: add a shadow definition for CollapsedTemplate. Tweak ViewTemplate shadow so "fold/unfold" and "focus" toolbar items automatically appear when using default templates. Remove error check for "CollapsedTemplate" existence, since shadow version will now always work as a fallback. |
|ELS 2/24/2006: added fallback to "CollapsedTemplate" if "WebCollapsedTemplate" is not found |
|ELS 2/6/2006: added check for 'readOnly' flag to use alternative "WebCollapsedTemplate" |
***/
//{{{
config.shadowTiddlers.CollapsedTemplate=
"<!--{{{-->\
<div class='toolbar' macro='toolbar expandTiddler collapseOthers closeTiddler closeOthers +editTiddler permalink references jump'></div>\
<div class='title' macro='view title'></div>\
<!--}}}-->";
// automatically tweak shadow ViewTemplate to add "collapseTiddler collapseOthers" commands
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/closeTiddler/,"collapseTiddler collapseOthers closeTiddler");
config.commands.collapseTiddler = {
text: "fold",
tooltip: "Collapse this tiddler",
collapsedTemplate: "CollapsedTemplate",
webCollapsedTemplate: "WebCollapsedTemplate",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
// don't fold tiddlers that are being edited!
if(story.isDirty(e.getAttribute("tiddler"))) return false;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(e);
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","true");
return false;
},
getCollapsedTemplate: function() {
if (readOnly&&store.tiddlerExists(this.webCollapsedTemplate))
return this.webCollapsedTemplate;
else
return this.collapsedTemplate
},
saveTemplate: function(e) {
if (e.getAttribute("savedTemplate")==undefined)
e.setAttribute("savedTemplate",e.getAttribute("template"));
},
// fold/unfold tiddler with suspend/resume of single/top/bottom-of-page mode
display: function(title,t) {
var opt=config.options;
var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
story.displayTiddler(null,title,t);
opt.chkBottomOfPageMode=saveBPM;
opt.chkTopOfPageMode=saveTPM;
opt.chkSinglePageMode=saveSPM;
}
}
config.commands.expandTiddler = {
text: "unfold",
tooltip: "Expand this tiddler",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
var t = e.getAttribute("savedTemplate");
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","false");
return false;
}
}
config.macros.collapseAll = {
text: "collapse all",
tooltip: "Collapse all tiddlers",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
createTiddlyButton(place,this.text,this.tooltip,function(){
story.forEachTiddler(function(title,tiddler){
if(story.isDirty(title)) return;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(tiddler);
config.commands.collapseTiddler.display(title,t);
tiddler.folded=true;
})
})
}
}
config.macros.expandAll = {
text: "expand all",
tooltip: "Expand all tiddlers",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
createTiddlyButton(place,this.text,this.tooltip,function(){
story.forEachTiddler(function(title,tiddler){
var t=config.commands.collapseTiddler.getCollapsedTemplate();
if(tiddler.getAttribute("template")!=t) return; // re-display only if collapsed
var t=tiddler.getAttribute("savedTemplate");
config.commands.collapseTiddler.display(title,t);
tiddler.folded=false;
})
})
}
}
config.commands.collapseOthers = {
text: "focus",
tooltip: "Expand this tiddler and collapse all others",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
story.forEachTiddler(function(title,tiddler) {
if(story.isDirty(title)) return;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
if (e==tiddler) t=e.getAttribute("savedTemplate");
config.commands.collapseTiddler.saveTemplate(tiddler);
config.commands.collapseTiddler.display(title,t);
tiddler.folded=(e!=tiddler);
})
return false;
}
}
// {{{<<foldFirst>>}}} macro forces tiddler to be folded when *initially* displayed.
// Subsequent re-render does NOT re-fold tiddler, but closing/re-opening tiddler DOES cause it to fold first again.
config.macros.foldFirst = {
handler: function(place,macroName,params,wikifier,paramString,tiddler){
var e=story.findContainingTiddler(place);
if (e.getAttribute("foldedFirst")=="true") return; // already been folded once
var title=e.getAttribute("tiddler")
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(e);
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","true");
e.setAttribute("foldedFirst","true"); // only when tiddler is first rendered
return false;
}
}
//}}}
<!--▐▌Customized the menu. Overriding the shadow tiddler provided by CollapseTiddlersPlugin -->
<div class='toolbar'>
<span macro='toolbar +editTiddler'></span>
<span macro='toolbar permalink references'>|</span>
<span macro='toolbar +expandTiddler collapseOthers closeOthers'>|</span>
<span macro='toolbar +closeTiddler'>|</span>
</div>
<table class="collapsedViewTable">
<tr>
<td class="collapsedViewTableTitle"><span class='title' macro='view title'></span> <span macro="miniTag"></span></td>
<td class="collapsedViewTableTags"><div class="tagglyTagged" macro="tags"></div></td>
<td class="collapsedViewTableKey"><span macro="showWhenTaggedAny ordered fav" style='margin-left:2em;'>
<span class='editorFooter' macro='message views.editor.orderKeyPrompt'></span>
<span class='title' macro='view orderingkey' style='text-align:left;'></span>
</span>
</td>
</tr>
</table>
<style type="text/css" media=screen>
<!--
table.collapsedViewTable { width:100%; }
td.collapsedViewTableTitle { width:10%; white-space:nowrap; }
td.collapsedViewTableTags { width:auto; padding-left:1.5em; }
td.collapsedViewTableKey { width:10%; white-space:nowrap; text-align:right; }
-->
</style>
Background: #fff
Foreground: #000
PrimaryPale: #ddd
PrimaryLight: #ddf
PrimaryMid: #069
PrimaryDark: #014
SecondaryPale: #f8f8ff
SecondaryLight: #fe8
SecondaryMid: #69c
SecondaryDark: #000
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
TerminalBorder: #9db9c8
TerminalForeground: #bbb
TerminalBackground: #000
CodeShade: #f0f0fd
/***
<<tiddler CookieManager>>
***/
/***
!!![[Portable cookies:|CookieSaverPlugin]] {{fine{<<option chkPortableCookies>>enable <<option chkMonitorCookieJar>>monitor}}}
^^This section is ''//__automatically maintained__//'' by [[CookieSaverPlugin]]. To block specific cookies, see [[CookieSaverPluginConfig]].^^
***/
//{{{
if (config.options.txtUserName=="YourName" && config.options.chkPortableCookies) {
config.options.txtTodoTabs="work";
config.options.txtProjectTabs="work";
}
//}}}
//{{{
if (config.options.txtUserName=="Rustem" && config.options.chkPortableCookies) {
config.options.txtTodoTabs="work";
config.options.txtProjectTabs="work";
config.options.txtMemorizeTabs="Vim";
config.options.txtTweakerSortBy="title";
}
//}}}
//{{{
if (config.options.txtUserName=="nameanyone" && config.options.chkPortableCookies) {
config.options.txtTodoTabs="work";
config.options.txtProjectTabs="work";
}
//}}}
// // /% end portable cookies %/
/***
|Name|CookieSaverPlugin|
|Source|http://www.TiddlyTools.com/#CookieSaverPlugin|
|Version|1.0.2|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|automatically save TiddlyWiki cookie options to [[CookieJar]] tiddler for portable settings|
|Status|BETA EXPERIMENTAL - USE WITH CAUTION - SUBJECT TO CHANGE|
!!!!!Usage
<<<
Whenever TiddlyWiki option settings or other 'stateful' program values are changed, a browser-based cookie value is typically added, removed, or changed. Each time this occurs, the CookieSaverPlugin generates an equivalent ''portable cookie'', which is a single line of javascript code that simply assigns a fixed value directly to the specific TiddlyWiki internal config.options.* variable corresponding to the browser cookie with the same name.
The portable cookies are automatically written into a tiddler named [[CookieJar]] that is tagged with<<tag systemConfig>>so that their values will be applied as soon as the document is saved and reloaded. You can change or delete an individual portable cookie by editing the contents of the [[CookieJar]] and removing the appropriate line of javascript from the tiddler source code. Note: editing the portable cookie definitions does not alter the values of any corresponding browser cookies, nor does it update the internal value that is in use within the current TiddlyWiki document session. Changes made directly to the [[CookieJar]] are only applied after saving and reloading the document. In any case, whenever a browser cookie value is updated, any modifications you made to the equivalent portable cookie are immediately rewritten to reflect the current browser cookie value.
Browser cookies are, obviously, stored with your browser... and are kept separate from the document itself. In contrast, because your portable cookies are stored in a [[CookieJar]] within the document, they remain part of that document.
When the document is copied and shared with others, each copy includes the [[CookieJar]] containing //your// stored portable cookies. Fortunately, CookieSaverPlugin can generate and maintain several separate sets of portable cookies in the same [[CookieJar]] tiddler, where each set is associated with a different TiddlyWiki username. As long as other readers have not chosen the same username, your portable cookie values will not be automatically applied when they are reading the document. Rather, as they interact with the document, a new set of portable cookies, associated with //their// username, will be automatically added to the [[CookieJar]].
In addition to tracking and applying separate portable cookies for each user, CookieSaverPlugin can also be configured so that sensitive data (such as internal URLs, email addresses, login IDs and passwords, etc.) will never be inadvertently stored in the [[CookieJar]]. To achieve this, you can selectively prevent specific cookienames from being used as portable cookies by placing a special javascript function definition in a tiddler named [[CookieSaverPluginConfig]], tagged with 'systemConfig':
{{{
config.macros.cookieSaver.allowPortableCookie=function(name){
if ( ... some test using 'name' ...) return false;
if ( ... another test with 'name' ...) return true;
etc.
return true; // default=allow
}
}}}
The allowPortableCookie() function offers a flexible method for plugin developers and other technically skilled document authors to implement their own custom-defined, application-specific cookie data protection by applying sophisticated logic for deciding which cookies should be allowed or blocked based on variety of different conditions. The basic operation of this function is to accept a cookie name as text input, apply some tests based on that cookie name (combined with any other useful criteria), and then return //true// if saving the portable cookie should be permitted, or //false// if the cookie should be excluded from the [[CookieJar]].
Unfortunately, although the technical expertise needed to write this test function is relatively minor, the level of programming ability that is needed can nonetheless be beyond the skills that many people possess. To help address this, CookieSaverPlugin also supports an alternative syntax that allows you to define a simple array of cookie names that is used by the plugin to automatically block the indicated names from being included as portable cookies in the [[CookieJar]]. The array definition syntax looks like this:
{{{
// define a complete set of blocked cookie names
config.macros.cookieSaver.blockedCookies=['cookie','cookie','cookie',etc...];
}}}
or
{{{
// add individual cookies names to the current set of blocked cookies
config.macros.cookieSaver.blockedCookies.push('cookie');
config.macros.cookieSaver.blockedCookies.push('cookie');
etc...
}}}
Note: the allowPortableCookie() function and the blockedCookies[] array are only used to limit the creation of portable cookies within the [[CookieJar]], and are //not// applied when creating normal browser cookies. Thus, regardless of whether or not a given portable cookie has been excluded or permitted, all the usual TiddlyWiki settings and internal state data can still be saved as secure, private, local browser cookies that are never made visible to others, even when the document is shared.
<<<
!!!!!Configuration
<<<
<<option chkPortableCookies>> allow ~CookieSaver to store //''portable cookies''// in [[CookieJar]] tiddler
<<option chkMonitorCookieJar>> monitor ~CookieSaver activity (show messages whenever [[CookieJar]] is updated)
<<option chkCookieJarAddToAdvancedOptions>> display [[CookieJar]] in [[AdvancedOptions]]
^^//note: changing this setting does not take effect until you reload the document//^^
<<<
!!!!!Revisions
<<<
2008.09.11 [1.0.2] automatically add portable cookies header to existing CookieJar (if any). Also, added chkMonitorCookieJar option to display CookieJar activity messages
2008.09.10 [1.0.1] documentation, code cleanup, improvements in 'allowPortableCookie()' function handling
2008.09.09 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.CookieSaverPlugin= {major: 1, minor: 0, revision: 2, date: new Date(2008,9,11)};
config.macros.cookieSaver = {
target:
config.options.txtCookieJar||"CookieJar",
init: function() {
if (config.options.chkPortableCookies===undefined)
config.options.chkPortableCookies=false;
if (config.options.txtCookieJar===undefined)
config.options.txtCookieJar=this.target;
if (config.options.chkCookieJarAddToAdvancedOptions===undefined)
config.options.chkCookieJarAddToAdvancedOptions=true;
if (config.options.chkCookieJarAddToAdvancedOptions)
config.shadowTiddlers.AdvancedOptions+="\n!!%0\n><<tiddler [[%0]]>>".format([this.target]);
if (config.options.chkMonitorCookieJar===undefined)
config.options.chkMonitorCookieJar=false;
// add empty Portable Cookies section to shadow CookieJar
var h="/***\n<<tiddler CookieManager>>\n***/\n";
var t=(config.shadowTiddlers[this.target]||"").replace(new RegExp(h.replace(/\*/g,'\\*'),''),'')
config.shadowTiddlers[this.target]=this.header+this.footer+t;
// add empty Portable Cookies section to real CookieJar (if one exists)
if (store.tiddlerExists(this.target) && !readOnly) {
var tid=this.get(this.target);
var t=tid.text;
if (t.indexOf(this.header)==-1){
t=this.header+this.footer+t.replace(new RegExp(h.replace(/\*/g,'\\*'),''),'');
var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
store.saveTiddler(tid.title,tid.title,t,who,when,tid.tags,tid.fields);
displayMessage("CookieSaver: added 'Portable Cookies' section to CookieJar");
}
}
// add "cookies" backstage task
if (config.tasks && !config.tasks.cookies) { // for TW2.2b3 or above
config.tasks.cookies = {
text: "cookies",
tooltip: "manage cookie-based option settings",
content: "{{groupbox{<<tiddler CookieManager>><<tiddler [[%0]]>>}}}".format([this.target])
}
config.backstageTasks.push("cookies");
}
},
header:
"/***\n<<tiddler CookieManager>>\n***/\n"
+"/***\n"
+"!!![[Portable cookies:|CookieSaverPlugin]] "
+"{{fine{<<option chkPortableCookies>>enable <<option chkMonitorCookieJar>>monitor}}}\n"
+"^^This section is ''//__automatically maintained__//'' by [[CookieSaverPlugin]]. "
+"To block specific cookies, see [[CookieSaverPluginConfig]].^^\n"
+"***/\n",
startUser:
"//{{{\n"
+"if (config.options.txtUserName==\"%0\" && config.options.chkPortableCookies) {",
endUser:
"\n}\n//}}}\n",
footer:
"// // /% end portable cookies %/\n",
get: function(tid) { // create or retrieve tiddler
if (story.isDirty(tid)) return null; // tiddler is being hand-edited... leave it alone.
var text=config.shadowTiddlers[this.target];
var who=config.options.txtUserName;
var when=new Date();
var tags=['systemConfig'];
return store.getTiddler(tid)||store.saveTiddler(tid,tid,text,who,when,tags,{});
},
format: function(name) {
if (name.substr(0,3)=='chk')
return '\tconfig.options.'+name+'='+(config.options[name]?'true;':'false;');
return '\tconfig.options.'+name+'="'+config.options[name]+'";';
},
blockedCookies: [],
allowPortableCookie: function(name) {
return true;
},
set: function(name) {
if (!name||!name.trim().length) return;
if (name=='txtUserName' || this.blockedCookies.contains(name) || !this.allowPortableCookie(name)) {
if (config.options.chkMonitorCookieJar && !startingUp)
displayMessage("CookieJar: blocked '"+name+"'");
return false; // don't save excluded cookies
}
var tid=this.get(this.target);
if (!tid) return false; // if no tiddler... do nothing
var t=tid.text;
if (t.indexOf(this.header)==-1) { // re-add Portable Cookies section if it was deleted by hand edit
var h="/***\n<<tiddler CookieManager>>\n***/\n";
t=this.header+this.footer+t.replace(new RegExp(h.replace(/\*/g,'\\*'),''),'');
}
var who=config.options.txtUserName;
var when=new Date();
var startmark=this.startUser.format([who]);
var endmark=this.endUser;
var startpos=t.indexOf(startmark);
if (startpos==-1) { // insert new user (just before footer)
if (config.options.chkMonitorCookieJar && !startingUp)
displayMessage("CookieJar: added new user '"+who+"'");
var addpos=t.indexOf(this.footer); if (addpos==-1) addpos=t.length;
t=t.substr(0,addpos)+startmark+endmark+t.substr(addpos);
startpos=addpos;
}
startpos+=startmark.length;
var endpos=t.indexOf(endmark,startpos);
var pre=t.substr(0,startpos);
var lines=t.substring(startpos,endpos).split('\n');
var post=t.substr(endpos);
var code=this.format(name);
var match='\tconfig.options.'+name+'=';
var found=false; var changed=false;
for (var i=0; i<lines.length; i++) { // find and replace existing setting
if (lines[i].substr(0,match.length)==match) {
found=true;
if (changed=lines[i]!=code) lines[i]=code; // replace value
if (config.options.chkMonitorCookieJar && !startingUp && changed)
displayMessage("CookieJar: "+code);
}
}
if (!found && code.length) { // OR, add new setting
lines[lines.length]=code;
if (config.options.chkMonitorCookieJar && !startingUp)
displayMessage("CookieJar: "+code);
}
if (found && !changed) return; // don't alter tiddler unless necessary
t=pre+lines.join('\n')+post;
var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
store.saveTiddler(this.target,this.target,t,who,when,tid.tags,tid.fields);
story.refreshTiddler(this.target,null,true);
},
remove: function(name) {
if (!name||!name.trim().length) return;
var who=config.options.txtUserName;
var when=new Date();
var tid=store.getTiddler(this.target);
if (!tid) return false; // if no tiddler... do nothing
var t=tid.text;
var who=config.options.txtUserName
var startmark=this.startUser.format([who]);
var endmark=this.endUser;
var startpos=t.indexOf(startmark);
if (startpos==-1) return false; // no such user... do nothing
startpos+=startmark.length;
var endpos=t.indexOf(endmark,startpos);
var pre=t.substr(0,startpos);
var lines=t.substring(startpos,endpos).split('\n');
var post=t.substr(endpos);
var match='\tconfig.options.'+name;
var found=false; var changed=false;
for (var i=0; i<lines.length; i++) { // find and remove setting
if (lines[i].substr(0,match.length)==match) {
lines.splice(i,1);
changed=true;
if (config.options.chkMonitorCookieJar && !startingUp)
displayMessage("CookieJar: deleted '"+name+"'");
break;
}
}
if (!changed) return; // not found... do nothing
t=pre+lines.join('\n')+post;
if (lines.length==1) { // no cookies left, remove user
t=pre.substr(0,pre.length-startmark.length)+post.substr(endmark.length);
if (config.options.chkMonitorCookieJar && !startingUp)
displayMessage("CookieJar: removed user '"+who+"'");
}
var who=config.options.chkForceMinorUpdate?tid.modifier:config.options.txtUserName;
var when=config.options.chkForceMinorUpdate?tid.modified:new Date();
store.saveTiddler(this.target,this.target,t,who,when,tid.tags,tid.fields);
story.refreshTiddler(this.target,null,true);
}
}
//}}}
//{{{
// Hijack saveOptionCookie() to add CookieSaver processing
config.macros.cookieSaver.saveOptionCookie=saveOptionCookie;
window.saveOptionCookie=function(name)
{
config.macros.cookieSaver.saveOptionCookie.apply(this,arguments);
if (!readOnly && (config.options.chkPortableCookies || name=="chkPortableCookies"))
config.macros.cookieSaver.set(name);
}
// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
window.removeCookie=function(name) {
document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;';
}
}
// ... and then hijack it to also remove any corresponding PortableCookie
config.macros.cookieSaver.removeCookie=removeCookie;
window.removeCookie=function(name)
{
if (config.options.chkPortableCookies && !readOnly)
config.macros.cookieSaver.remove(name);
config.macros.cookieSaver.removeCookie.apply(this,arguments);
}
//}}}
/***
|Name|CookieSaverPluginConfig|
|Source|http://www.TiddlyTools.com/#CookieSaverPluginConfig|
|Requires|CookieSaverPlugin|
|Description|custom settings for [[CookieSaverPlugin]]|
!!!!!Portable Cookie Configuration:
***/
// // <<option chkPortableCookies>> allow ~CookieSaver to store //''portable cookies''// in [[CookieJar]] tiddler
// // <<option chkMonitorCookieJar>> monitor ~CookieSaver activity (show messages whenever [[CookieJar]] is updated)
//{{{
// default to these settings:
// config.options.chkPortableCookies=false; // when FALSE this blocks ALL portable cookies
// config.options.chkMonitorCookieJar=false;
//}}}
// // Individual cookie names can be added to the {{{config.macros.cookieSaver.blockedCookies}}} array to prevent them from being stored in the [[CookieJar]].
//{{{
var bc=config.macros.cookieSaver.blockedCookies;
bc.push("chkBackstage"); // core
bc.push("txtMainTab"); // TiddlyWiki: SideBarTabs
bc.push("txtTOCSortBy"); // TiddlyTools: TableOfContentsPlugin
bc.push("txtCatalogTab"); // TiddlyTools: ShowCatalog
bc.push("txtUploadFilename"); // BidiX: UploadPlugin
bc.push("txtUploadDir"); // BidiX: UploadPlugin
bc.push("pasPassword"); // BidiX: UploadPlugin
bc.push("pasUploadPassword"); // BidiX: UploadPlugin
//}}}
// // You can also define a javascript test function that determines whether or not any particular cookie name should be stored in the [[CookieJar]]. The following function should return FALSE if the portable cookie should be blocked, or TRUE if the cookie should be allowed:
//{{{
config.macros.cookieSaver.allowPortableCookie=function(name) {
// add tests based on specific cookie names and runtime conditions
if (name.substr(0,9)=="chkSlider") return false; // NestedSlidersPlugin
if (name.substr(0,13)=="txtFirstVisit") return false; // VisitCounter
if (name.substr(0,12)=="txtLastVisit") return false; // VisitCounter
if (name.substr(0,13)=="txtVisitCount") return false; // VisitCounter
return true;
}
//}}}
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version|use with TW2.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.2.0|
|Type|plugin|
|Requires||
|Overrides|various|
|Description|a small collection of overrides to TW core functions|
This tiddler contains changes TW core functions to provide minor changes in standard features or behavior. It is hoped that some of these tweaks may someday be added into the TW core, so that these adjustments will be available without needing these add-on definitions.
>''Note: the changes contained in this tiddler are generally applicable for version 2.4.3 of TiddlyWiki.''
>Please view [[CoreTweaksArchive]] for tweaks that may be used with earlier versions of TiddlyWiki.
***/
//{{{
// calculate TW version number - used to determine which tweaks should be applied
var ver=version.major+version.minor/10+version.revision/100;
//}}}
/***
----
***/
// // open tickets:
// // {{block{
/***
!!!890 add conditional test to """<<tiddler>>""" macro
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/890 - OPEN
This tweak extends the {{{<<tiddler>>}}} macro syntax so you can include a javascript-based //test expression// to determine if the tiddler transclusion should be performed:
{{{
<<tiddler TiddlerName if:{{...}} with: param param etc.>>
}}}
If the test is ''true'', then the tiddler is transcluded as usual. If the test is ''false'', then the transclusion is skipped and //no output is produced//.
***/
//{{{
config.macros.tiddler.if_handler = config.macros.tiddler.handler;
config.macros.tiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
params = paramString.parseParams('name',null,true,false,true);
if (!getParam(params,'if',true)) return;
this.if_handler.apply(this,arguments);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!831 backslash-quoting for embedding newlines in 'line-mode' formats
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/831 - OPEN
This tweak pre-processes source content to convert 'double-backslash-newline' into {{{<br>}}} before wikify(), so that literal newlines can be embedded in line-mode wiki syntax (e.g., tables, bullets, etc.)
***/
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
if (source) arguments[0]=source.replace(/\\\\\n/mg,'<br>');
coreWikify.apply(this,arguments);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!829 """<<tag>>""" macro - sortby parameter
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/829 - OPEN
This tweak adds an optional 'sortby' parameter to the """<<tag tagname label tip sortby>>""" macro, as well as the """<<allTags excludeTag sortby>>""" macro used to generate the sidebar contents 'tags' list. Specify the field on which the contents of each tag popup is to be sorted, with a '+' or '-' prefix to indicate ascending/descending order, respectively.
Example: """<<tag systemConfig "plugins" "list plugins by date, most recent first" "-modified">>"""
Try it: <<tag systemConfig "plugins" "list plugins by date, most recent first" "-modified">>
Similarly, to change the sort order used by the popups from all tags shown in the sidebar contents, edit the [[TagTags]] shadow tiddler and enter: """<<allTags excludeLists -modified>>"""
***/
//{{{
// hijack tag handler() to add 'sortby' attribute to tag button
config.macros.tag.CoreTweaksSortTags_handler=config.macros.tag.handler;
config.macros.tag.handler = function(place,macroName,params)
{
this.CoreTweaksSortTags_handler.apply(this,arguments);
var btn=place.lastChild;
if (params[3]) btn.setAttribute('sortby',params[3]);
}
// tweak <<allTags>> macro to add 'sortby' attribute to each tag button
var fn=config.macros.allTags.handler;
var lines=fn.toString().split('\n');
lines.splice(lines.length-2,0,['if(params[1]) btn.setAttribute("sortby",params[1]);']);
fn=lines.join('\n');
eval('config.macros.allTags.handler='+fn);
// tweak tag event handler to:
// * use tag filtering (only if '[' is present in tag value)
// * use optional 'sortby' attribute
// * save 'sortby' value in 'open all' command (for displaying tiddlers in sorted order)
var fn=onClickTag;
fn=fn.toString().replace(
/store.getTaggedTiddlers\(tag\);/g,
'(tag.indexOf("[")==-1?store.getTaggedTiddlers(tag):store.filterTiddlers(tag));'
+'var sortby=this.getAttribute("sortby");'
+'if(sortby&&sortby.length) store.sortTiddlers(tagged,sortby);'
);
fn=fn.toString().replace(
/openAll.setAttribute\("tag",\s*tag\);/g,
'openAll.setAttribute("tag",tag); openAll.setAttribute("sortby",sortby);'
);
eval(fn);
// tweak 'open all' event handler to use 'sortby' attribute
var fn=onClickTagOpenAll;
fn=fn.toString().replace(
/story.displayTiddlers\(this,\s*tiddlers\);/g,
'var sortby=this.getAttribute("sortby");'
+'if(sortby&&sortby.length) store.sortTiddlers(tiddlers,sortby);'
+'story.displayTiddlers(this,tiddlers);'
);
eval(fn);
//}}}
// // }}}}}}// // {{block{
/***
!!!824 ~WindowTitle - alternative to combined ~SiteTitle/~SiteSubtitle in window titlebar
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/824 - OPEN
This tweak allows definition of an optional [[WindowTitle]] tiddler that, when present, provides alternative text for display in the browser window's titlebar, instead of using the combined text content from [[SiteTitle]] and [[SiteSubtitle]] (which will still be displayed as usual in the TiddlyWiki document header area).
Note: this ticket replaces http://trac.tiddlywiki.org/ticket/401 (closed), which proposed using a custom [[PageTitle]] tiddler for this purpose. ''If you were using the previous '401 ~PageTitle' tweak, you will need to rename [[PageTitle]] to [[WindowTitle]] to continue to use your custom window title text''
***/
//{{{
config.shadowTiddlers.WindowTitle='<<tiddler SiteTitle>> - <<tiddler SiteSubtitle>>';
window.getPageTitle=function() { return wikifyPlain('WindowTitle'); }
store.addNotification('WindowTitle',refreshPageTitle); // so title stays in sync with tiddler changes
//}}}
// // }}}}}}// // {{block{
/***
!!!784 allow tiddler sections in TiddlyLinks to be used as anchor points for intra-tiddler scrolling.
>http://trac.tiddlywiki.org/ticket/784 - OPEN - Please see separate [[SectionLinksPlugin]]
!!!683 FireFox3 Import bug: 'browse' button replacement
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/683 - OPEN
The web standard 'type=file' input control that has been used as a local path/file picker for TiddlyWiki no longer works as expected in FireFox3, which has, for security reasons, limited javascript access to this control so that *no* local filesystem path information can be revealed, even when it is intentional and necessary, as it is with TiddlyWiki. This tweak provides alternative HTML source that patches the backstage import panel. It replaces the 'type=file' input control with a text+button combination of controls that invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
>Note: ''This tweak also requires http://trac.tiddlywiki.org/ticket/604 - cross-platform askForFilename()''
***/
//{{{
if (window.Components) {
var fixhtml='<input name="txtBrowse" style="width:30em"><input type="button" value="..."'
+' onClick="window.browseForFilename(this.previousSibling,true)">';
var cmi=config.macros.importTiddlers;
cmi.step1Html=cmi.step1Html.replace(/<input type='file' size=50 name='txtBrowse'>/,fixhtml);
}
merge(config.messages,{selectFile:'Please enter or select a file'}); // ready for I18N translation
window.browseForFilename=function(target,mustExist) { // note: both params are optional
var msg=config.messages.selectFile;
if (target && target.title) msg=target.title; // use target field tooltip (if any) as dialog prompt text
// get local path for current document
var path=getLocalPath(document.location.href);
var p=path.lastIndexOf('/'); if (p==-1) p=path.lastIndexOf('\\'); // Unix or Windows
if (p!=-1) path=path.substr(0,p+1); // remove filename, leave trailing slash
var file=''
var result=window.askForFilename(msg,path,file,mustExist); // requires #604
if (target && result.length) // set target field and trigger handling
{ target.value=result; target.onchange(); }
return result;
}
//}}}
// // }}}}}}// // {{block{
/***
!!!604 cross-platform askForFilename()
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/604 - OPEN
invokes a system-native secure 'file-chooser' dialog box to provide TiddlyWiki with access to a complete path+filename so that TW functions properly locate user-selected local files.
***/
//{{{
window.askForFilename=function(msg,path,file,mustExist) {
var r = window.mozAskForFilename(msg,path,file,mustExist);
if(r===null || r===false)
r = window.ieAskForFilename(msg,path,file,mustExist);
if(r===null || r===false)
r = window.javaAskForFilename(msg,path,file,mustExist);
if(r===null || r===false)
r = prompt(msg,path+file);
return r||'';
}
window.mozAskForFilename=function(msg,path,file,mustExist) {
if(!window.Components) return false;
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, mustExist?nsIFilePicker.modeOpen:nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='html';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel)
var result=picker.file.persistentDescriptor;
}
catch(ex) { displayMessage(ex.toString()); }
return result;
}
window.ieAskForFilename=function(msg,path,file,mustExist) {
if(!config.browser.isIE) return false;
try {
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
s.FilterIndex=3; // default to HTML files;
s.InitialDir=path;
s.FileName=file;
return s.showOpen()?s.FileName:'';
}
catch(ex) { displayMessage(ex.toString()); }
return result;
}
window.javaAskForFilename=function(msg,path,file,mustExist) {
if(!document.applets['TiddlySaver']) return false;
// TBD: implement java-based askFile(...) function
try { return document.applets['TiddlySaver'].askFile(msg,path,file,mustExist); }
catch(ex) { displayMessage(ex.toString()); }
}
//}}}
// // }}}}}}// // {{block{
/***
!!!657 wrap tabs onto multiple lines
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/657 - OPEN
This tweak inserts an extra space element following each tab, allowing them to wrap onto multiple lines if needed.
***/
//{{{
config.macros.tabs.handler = function(place,macroName,params)
{
var cookie = params[0];
var numTabs = (params.length-1)/3;
var wrapper = createTiddlyElement(null,'div',null,'tabsetWrapper ' + cookie);
var tabset = createTiddlyElement(wrapper,'div',null,'tabset');
tabset.setAttribute('cookie',cookie);
var validTab = false;
for(var t=0; t<numTabs; t++) {
var label = params[t*3+1];
var prompt = params[t*3+2];
var content = params[t*3+3];
var tab = createTiddlyButton(tabset,label,prompt,this.onClickTab,'tab tabUnselected');
createTiddlyElement(tab,'span',null,null,' ',{style:'font-size:0pt;line-height:0px'}); // ELS
tab.setAttribute('tab',label);
tab.setAttribute('content',content);
tab.title = prompt;
if(config.options[cookie] == label)
validTab = true;
}
if(!validTab)
config.options[cookie] = params[1];
place.appendChild(wrapper);
this.switchTab(tabset,config.options[cookie]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!628 hide 'no such macro' errors
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/628 - OPEN
When invoking a macro that is not defined, this tweak prevents the display of the 'error in macro... no such macro' message. This is useful when rendering tiddler content or templates that reference macros that are defined by //optional// plugins that have not been installed in the current document.
<<option chkHideMissingMacros>> hide 'no such macro' error messages
***/
//{{{
if (config.options.chkHideMissingMacros===undefined)
config.options.chkHideMissingMacros=false;
window.coreTweaks_missingMacro_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
if (!config.macros[macro] || !config.macros[macro].handler)
if (config.options.chkHideMissingMacros) return;
window.coreTweaks_missingMacro_invokeMacro.apply(this,arguments);
}
//}}}
// // }}}}}}// // {{block{
/***
!!!608/609/610 toolbars - toggles, separators and transclusion
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/608 - OPEN (more/less toggle)
http://trac.tiddlywiki.org/ticket/609 - OPEN (separators)
http://trac.tiddlywiki.org/ticket/610 - OPEN (wikify tiddler/slice/section content)
This combination tweak extends the """<<toolbar>>""" macro to add use of '<' to insert a 'less' menu command (the opposite of '>' == 'more'), as well as use of '*' to insert linebreaks and "!" to insert a vertical line separator between toolbar items. In addition, this tweak add the ability to use references to tiddlernames, slices, or sections and render their content inline within the toolbar, allowing easy creation of new toolbar commands using TW content (such as macros, links, inline scripts, etc.)
To produce a one-line style, with "less" at the end, use
| ViewToolbar| foo bar baz > yabba dabba doo < |
resulting in:
{{{
foo bar baz more
and
foo bar baz yabba dabba doo less
}}}
or to use the CoreTweaks? two-line style:
| ViewToolbar| foo bar baz > < * yabba dabba doo |
which would produce:
{{{
foo bar baz more
and
foo bar baz less
yabba dabba doo
}}}
''see [[ToolbarCommands]] for examples of how these features can be used''
***/
//{{{
merge(config.macros.toolbar,{
moreLabel: 'more\u25BC',
morePrompt: 'Show additional commands',
lessLabel: '\u25C4less',
lessPrompt: 'Hide additional commands',
separator: '|'
});
config.macros.toolbar.onClickMore = function(ev) {
var e = this.nextSibling;
e.style.display = 'inline'; // show menu
this.style.display = 'none'; // hide button
return false;
};
config.macros.toolbar.onClickLess = function(ev) {
var e = this.parentNode;
var m = e.previousSibling;
e.style.display = 'none'; // hide menu
m.style.display = 'inline'; // show button
return false;
};
config.macros.toolbar.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
for(var t=0; t<params.length; t++) {
var c = params[t];
switch(c) {
case '!': // ELS - SEPARATOR (added)
createTiddlyText(place,this.separator);
break;
case '*': // ELS - LINEBREAK (added)
createTiddlyElement(place,'BR');
break;
case '<': // ELS - LESS COMMAND (added)
var btn = createTiddlyButton(place,
this.lessLabel,this.lessPrompt,config.macros.toolbar.onClickLess,'moreCommand');
break;
case '>':
var btn = createTiddlyButton(place,
this.moreLabel,this.morePrompt,config.macros.toolbar.onClickMore,'moreCommand');
var e = createTiddlyElement(place,'span',null,'moreCommand');
e.style.display = 'none';
place = e;
break;
default:
var theClass = '';
switch(c.substr(0,1)) {
case '+':
theClass = 'defaultCommand';
c = c.substr(1);
break;
case '-':
theClass = 'cancelCommand';
c = c.substr(1);
break;
}
if(c in config.commands)
this.createCommand(place,c,tiddler,theClass);
else { // ELS - WIKIFY TIDDLER/SLICE/SECTION (added)
if (c.substr(0,1)=='~') c=c.substr(1); // ignore leading ~
var txt=store.getTiddlerText(c);
if (txt) {
// trim any leading/trailing newlines
txt=txt.replace(/^\n*/,'').replace(/\n*$/,'');
// trim PRE format wrapper if any
txt=txt.replace(/^\{\{\{\n/,'').replace(/\n\}\}\}$/,'');
// render content into toolbar
wikify(txt,createTiddlyElement(place,'span'),null,tiddler);
}
} // ELS - end WIKIFY CONTENT
break;
}
}
};
//}}}
// // }}}}}}// // {{block{
/***
!!!529 IE fixup - case-sensitive element lookup of tiddler elements
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/529 - OPEN
This tweak hijacks the standard browser function, document.getElementById(), to work-around the case-INsensitivity error in Internet Explorer (all versions up to and including IE7) //''Note: This tweak is only applied when using IE, and only for lookups of rendered tiddler elements within the containing 'tiddlerDisplay' element.''//
***/
//{{{
if (config.browser.isIE) {
document.coreTweaks_coreGetElementById=document.getElementById;
document.getElementById=function(id) {
var e=document.coreTweaks_coreGetElementById(id);
if (!e || !e.parentNode || e.parentNode.id!='tiddlerDisplay') return e;
for (var i=0; i<e.parentNode.childNodes.length; i++)
if (id==e.parentNode.childNodes[i].id) return e.parentNode.childNodes[i];
return null;
};
}
//}}}
// // }}}}}}// // {{block{
/***
!!!471 'creator' field for new tiddlers
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/471 - OPEN
This tweak HIJACKS the core's saveTiddler() function to automatically add a 'creator' field to a tiddler when it is FIRST created. You can use """<<view creator>>""" (or """<<view creator wikified>>""" if you prefer) to show this value embedded directly within the tiddler content, or {{{<span macro="view creator"></span>}}} in the ViewTemplate and/or EditTemplate to display the creator value in each tiddler.
***/
//{{{
// hijack saveTiddler()
TiddlyWiki.prototype.CoreTweaks_creatorSaveTiddler=TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler=function(title,newTitle,newBody,modifier,modified,tags,fields)
{
var existing=store.tiddlerExists(title);
var tiddler=this.CoreTweaks_creatorSaveTiddler.apply(this,arguments);
if (!existing) store.setValue(title,'creator',config.options.txtUserName);
return tiddler;
}
//}}}
// // }}}}}}
// // closed: won't fix //(leave as core tweaks)//
// // {{block{
/***
!!!637 TiddlyLink tooltip - custom formatting
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/637 - CLOSED: WON'T FIX
This tweak modifies the tooltip format that appears when you mouseover a link to a tiddler. It adds an option to control the date format, as well as displaying the size of the tiddler (in bytes)
Tiddler link tooltip format:
{{stretch{<<option txtTiddlerLinkTootip>>}}}
^^where: %0=title, %1=username, %2=modification date, %3=size in bytes, %4=description slice^^
Tiddler link tooltip date format:
{{stretch{<<option txtTiddlerLinkTooltipDate>>}}}
***/
//{{{
config.messages.tiddlerLinkTooltip='%0 - %1, %2 (%3 bytes) - %4';
config.messages.tiddlerLinkTooltipDate='DDD, MMM DDth YYYY 0hh12:0mm AM';
config.options.txtTiddlerLinkTootip=
config.options.txtTiddlerLinkTootip||config.messages.tiddlerLinkTooltip;
config.options.txtTiddlerLinkTooltipDate=
config.options.txtTiddlerLinkTooltipDate||config.messages.tiddlerLinkTooltipDate;
Tiddler.prototype.getSubtitle = function() {
var modifier = this.modifier;
if(!modifier) modifier = config.messages.subtitleUnknown;
var modified = this.modified;
if(modified) modified = modified.formatString(config.options.txtTiddlerLinkTooltipDate);
else modified = config.messages.subtitleUnknown;
var descr=store.getTiddlerSlice(this.title,'Description')||'';
return config.options.txtTiddlerLinkTootip.format([this.title,modifier,modified,this.text.length,descr]);
};
//}}}
// // }}}}}}// // {{block{
/***
!!!607 add HREF link on permaview command
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/607 - CLOSED: WON'T FIX
This tweak automatically sets the HREF for the 'permaview' sidebar command link so you can use the 'right click' context menu for faster, easier bookmarking. Note that this does ''not'' automatically set the permaview in the browser's current location URL... it just sets the HREF on the command link. You still have to click the link to apply the permaview.
***/
//{{{
config.macros.permaview.handler = function(place)
{
var btn=createTiddlyButton(place,this.label,this.prompt,this.onClick);
addEvent(btn,'mouseover',this.setHREF);
addEvent(btn,'focus',this.setHREF);
};
config.macros.permaview.setHREF = function(event){
var links = [];
story.forEachTiddler(function(title,element) {
links.push(String.encodeTiddlyLink(title));
});
var newURL=document.location.href;
var hashPos=newURL.indexOf('#');
if (hashPos!=-1) newURL=newURL.substr(0,hashPos);
this.href=newURL+'#'+encodeURIComponent(links.join(' '));
}
//}}}
// // }}}}}}// // {{block{
/***
!!!458 add permalink-like HREFs on internal TiddlyLinks
***/
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/458 - CLOSED: WON'T FIX
This tweak assigns a permalink-like HREF to internal Tiddler links (which normally do not have any HREF defined). This permits the link's context menu (right-click) to include 'open link in another window/tab' command. Based on a request from Dustin Spicuzza.
***/
//{{{
window.coreTweaks_createTiddlyLink=window.createTiddlyLink;
window.createTiddlyLink=function(place,title,includeText,theClass,isStatic,linkedFromTiddler,noToggle)
{
// create the core button, then add the HREF (to internal links only)
var link=window.coreTweaks_createTiddlyLink.apply(this,arguments);
if (!isStatic)
link.href=document.location.href.split('#')[0]+'#'+encodeURIComponent(String.encodeTiddlyLink(title));
return link;
}
//}}}
// // }}}}}}
// // <<foldHeadings>>
/***
|''Name:''|CryptoFunctionsPlugin|
|''Description:''|Support for cryptographic functions|
***/
//{{{
if(!version.extensions.CryptoFunctionsPlugin) {
version.extensions.CryptoFunctionsPlugin = {installed:true};
//--
//-- Crypto functions and associated conversion routines
//--
// Crypto "namespace"
function Crypto() {}
// Convert a string to an array of big-endian 32-bit words
Crypto.strToBe32s = function(str)
{
var be = Array();
var len = Math.floor(str.length/4);
var i, j;
for(i=0, j=0; i<len; i++, j+=4) {
be[i] = ((str.charCodeAt(j)&0xff) << 24)|((str.charCodeAt(j+1)&0xff) << 16)|((str.charCodeAt(j+2)&0xff) << 8)|(str.charCodeAt(j+3)&0xff);
}
while (j<str.length) {
be[j>>2] |= (str.charCodeAt(j)&0xff)<<(24-(j*8)%32);
j++;
}
return be;
};
// Convert an array of big-endian 32-bit words to a string
Crypto.be32sToStr = function(be)
{
var str = "";
for(var i=0;i<be.length*32;i+=8)
str += String.fromCharCode((be[i>>5]>>>(24-i%32)) & 0xff);
return str;
};
// Convert an array of big-endian 32-bit words to a hex string
Crypto.be32sToHex = function(be)
{
var hex = "0123456789ABCDEF";
var str = "";
for(var i=0;i<be.length*4;i++)
str += hex.charAt((be[i>>2]>>((3-i%4)*8+4))&0xF) + hex.charAt((be[i>>2]>>((3-i%4)*8))&0xF);
return str;
};
// Return, in hex, the SHA-1 hash of a string
Crypto.hexSha1Str = function(str)
{
return Crypto.be32sToHex(Crypto.sha1Str(str));
};
// Return the SHA-1 hash of a string
Crypto.sha1Str = function(str)
{
return Crypto.sha1(Crypto.strToBe32s(str),str.length);
};
// Calculate the SHA-1 hash of an array of blen bytes of big-endian 32-bit words
Crypto.sha1 = function(x,blen)
{
// Add 32-bit integers, wrapping at 32 bits
add32 = function(a,b)
{
var lsw = (a&0xFFFF)+(b&0xFFFF);
var msw = (a>>16)+(b>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
};
// Add five 32-bit integers, wrapping at 32 bits
add32x5 = function(a,b,c,d,e)
{
var lsw = (a&0xFFFF)+(b&0xFFFF)+(c&0xFFFF)+(d&0xFFFF)+(e&0xFFFF);
var msw = (a>>16)+(b>>16)+(c>>16)+(d>>16)+(e>>16)+(lsw>>16);
return (msw<<16)|(lsw&0xFFFF);
};
// Bitwise rotate left a 32-bit integer by 1 bit
rol32 = function(n)
{
return (n>>>31)|(n<<1);
};
var len = blen*8;
// Append padding so length in bits is 448 mod 512
x[len>>5] |= 0x80 << (24-len%32);
// Append length
x[((len+64>>9)<<4)+15] = len;
var w = Array(80);
var k1 = 0x5A827999;
var k2 = 0x6ED9EBA1;
var k3 = 0x8F1BBCDC;
var k4 = 0xCA62C1D6;
var h0 = 0x67452301;
var h1 = 0xEFCDAB89;
var h2 = 0x98BADCFE;
var h3 = 0x10325476;
var h4 = 0xC3D2E1F0;
for(var i=0;i<x.length;i+=16) {
var j,t;
var a = h0;
var b = h1;
var c = h2;
var d = h3;
var e = h4;
for(j = 0;j<16;j++) {
w[j] = x[i+j];
t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=16;j<20;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),d^(b&(c^d)),w[j],k1);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=20;j<40;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k2);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=40;j<60;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),(b&c)|(d&(b|c)),w[j],k3);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
for(j=60;j<80;j++) {
w[j] = rol32(w[j-3]^w[j-8]^w[j-14]^w[j-16]);
t = add32x5(e,(a>>>27)|(a<<5),b^c^d,w[j],k4);
e=d; d=c; c=(b>>>2)|(b<<30); b=a; a = t;
}
h0 = add32(h0,a);
h1 = add32(h1,b);
h2 = add32(h2,c);
h3 = add32(h3,d);
h4 = add32(h4,e);
}
return Array(h0,h1,h2,h3,h4);
};
}
//}}}
/***
|Name|DatePlugin|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|formatted dates plus popup menu with 'journal' link, changes and (optional) reminders|
There are quite a few calendar generators, reminders, to-do lists, 'dated tiddlers' journals, blog-makers and GTD-like schedule managers that have been built around TW. While they all have different purposes, and vary in format, interaction, and style, in one way or another each of these plugins displays and/or uses date-based information to make finding, accessing and managing relevant tiddlers easier. This plugin provides a general approach to embedding dates and date-based links/menus within tiddler content.
!!!!!Documentation
>see [[DatePluginInfo]]
!!!!!Configuration
<<<
<<option chkDatePopupHideCreated>> omit 'created' section from date popups
<<option chkDatePopupHideChanged>> omit 'changed' section from date popups
<<option chkDatePopupHideTagged>> omit 'tagged' section from date popups
<<option chkDatePopupHideReminders>> omit 'reminders' section from date popups
<<option chkShowJulianDate>> display Julian day number (1-365) below current date
see [[DatePluginConfig]] for additional configuration settings, for use in calendar displays, including:
*date formats
*color-coded backgrounds
*annual fixed-date holidays
*weekends
<<<
!!!!!Revisions
<<<
2008.03.08 [2.7.0] in addModifiedsToPopup(), if a tiddler was created on the specified date, don't list it in the 'changed' section of the popup. Based on a request from Kashgarinn.
|please see [[DatePluginInfo]] for additional revision details|
2005.10.30 [0.9.0] pre-release
<<<
!!!!!Code
***/
//{{{
version.extensions.date = {major: 2, minor: 7, revision: 0, date: new Date(2008,3,8)};
config.macros.date = {
format: "YYYY.0MM.0DD", // default date display format
linkformat: "YYYY.0MM.0DD", // 'dated tiddler' link format
linkedbg: "#babb1e", // "babble"
todaybg: "#ffab1e", // "fable"
weekendbg: "#c0c0c0", // "cocoa"
holidaybg: "#ffaace", // "face"
createdbg: "#bbeeff", // "beef"
modifiedsbg: "#bbeeff", // "beef"
remindersbg: "#c0ffee", // "coffee"
holidays: [ "01/01", "07/04", "07/24", "11/24" ], // NewYearsDay, IndependenceDay(US), Eric's Birthday (hooray!), Thanksgiving(US)
weekend: [ 1,0,0,0,0,0,1 ] // [ day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6 ]
};
config.macros.date.handler = function(place,macroName,params)
{
// do we want to see a link, a popup, or just a formatted date?
var mode="display";
if (params[0]=="display") { mode=params[0]; params.shift(); }
if (params[0]=="popup") { mode=params[0]; params.shift(); }
if (params[0]=="link") { mode=params[0]; params.shift(); }
// get the date
var now = new Date();
var date = now;
if (!params[0] || params[0]=="today")
{ params.shift(); }
else if (params[0]=="filedate")
{ date=new Date(document.lastModified); params.shift(); }
else if (params[0]=="tiddler")
{ date=store.getTiddler(story.findContainingTiddler(place).id.substr(7)).modified; params.shift(); }
else if (params[0].substr(0,8)=="tiddler:")
{ var t; if ((t=store.getTiddler(params[0].substr(8)))) date=t.modified; params.shift(); }
else {
var y = eval(params.shift().replace(/Y/ig,(now.getYear()<1900)?now.getYear()+1900:now.getYear()));
var m = eval(params.shift().replace(/M/ig,now.getMonth()+1));
var d = eval(params.shift().replace(/D/ig,now.getDate()+0));
date = new Date(y,m-1,d);
}
// date format with optional custom override
var format=this.format; if (params[0]) format=params.shift();
var linkformat=this.linkformat; if (params[0]) linkformat=params.shift();
showDate(place,date,mode,format,linkformat);
}
window.showDate=showDate;
function showDate(place,date,mode,format,linkformat,autostyle,weekend)
{
if (!mode) mode="display";
if (!format) format=config.macros.date.format;
if (!linkformat) linkformat=config.macros.date.linkformat;
if (!autostyle) autostyle=false;
// format the date output
var title = date.formatString(format);
var linkto = date.formatString(linkformat);
// just show the formatted output
if (mode=="display") { place.appendChild(document.createTextNode(title)); return; }
// link to a 'dated tiddler'
var link = createTiddlyLink(place, linkto, false);
link.appendChild(document.createTextNode(title));
link.title = linkto;
link.date = date;
link.format = format;
link.linkformat = linkformat;
// if using a popup menu, replace click handler for dated tiddler link
// with handler for popup and make link text non-italic (i.e., an 'existing link' look)
if (mode=="popup") {
link.onclick = onClickDatePopup;
link.style.fontStyle="normal";
}
// format the popup link to show what kind of info it contains (for use with calendar generators)
if (autostyle) setDateStyle(place,link,weekend);
}
//}}}
//{{{
// NOTE: This function provides default logic for setting the date style when displayed in a calendar
// To customize the date style logic, please see[[DatePluginConfig]]
function setDateStyle(place,link,weekend) {
// alias variable names for code readability
var date=link.date;
var fmt=link.linkformat;
var linkto=date.formatString(fmt);
var cmd=config.macros.date;
if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=""))
{ place.style.background = cmd.weekendbg; }
if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
{ link.style.fontStyle="normal"; link.style.fontWeight="bold"; }
if (hasReminders(date))
{ link.style.textDecoration="underline"; }
if (isToday(date))
{ link.style.border="1px solid black"; }
if (isHoliday(date)&&(cmd.holidaybg!=""))
{ place.style.background = cmd.holidaybg; }
if (hasCreateds(date)&&(cmd.createdbg!=""))
{ place.style.background = cmd.createdbg; }
if (hasModifieds(date)&&(cmd.modifiedsbg!=""))
{ place.style.background = cmd.modifiedsbg; }
if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=""))
{ place.style.background = cmd.linkedbg; }
if (hasReminders(date)&&(cmd.remindersbg!=""))
{ place.style.background = cmd.remindersbg; }
if (isToday(date)&&(cmd.todaybg!=""))
{ place.style.background = cmd.todaybg; }
if (config.options.chkShowJulianDate) { // optional display of Julian date numbers
var m=[0,31,59,90,120,151,181,212,243,273,304,334];
var d=date.getDate()+m[date.getMonth()];
var y=date.getFullYear();
if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0)
d++; // after February in a leap year
wikify("@@font-size:80%;<br>"+d+"@@",place);
}
}
//}}}
//{{{
function isToday(date) // returns true if date is today
{ var now=new Date(); return ((now-date>=0) && (now-date<86400000)); }
function isWeekend(date) // returns true if date is a weekend
{ return (config.macros.date.weekend[date.getDay()]); }
function isHoliday(date) // returns true if date is a holiday
{
var longHoliday = date.formatString("0MM/0DD/YYYY");
var shortHoliday = date.formatString("0MM/0DD");
for(var i = 0; i < config.macros.date.holidays.length; i++) {
var holiday=config.macros.date.holidays[i];
if (holiday==longHoliday||holiday==shortHoliday) return true;
}
return false;
}
//}}}
//{{{
// Event handler for clicking on a day popup
function onClickDatePopup(e)
{
if (!e) var e = window.event;
var theTarget = resolveTarget(e);
var popup = Popup.create(this);
if(popup) {
// always show dated tiddler link (or just date, if readOnly) at the top...
if (!readOnly || store.tiddlerExists(this.date.formatString(this.linkformat)))
createTiddlyLink(popup,this.date.formatString(this.linkformat),true);
else
createTiddlyText(popup,this.date.formatString(this.linkformat));
if (!config.options.chkDatePopupHideCreated)
addCreatedsToPopup(popup,this.date,this.format);
if (!config.options.chkDatePopupHideChanged)
addModifiedsToPopup(popup,this.date,this.format);
if (!config.options.chkDatePopupHideTagged)
addTaggedToPopup(popup,this.date,this.linkformat);
if (!config.options.chkDatePopupHideReminders)
addRemindersToPopup(popup,this.date,this.linkformat);
}
Popup.show(popup,false);
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
return(false);
}
//}}}
//{{{
function indexCreateds() // build list of tiddlers, hash indexed by creation date
{
var createds= { };
var tiddlers = store.getTiddlers("title","excludeLists");
for (var t = 0; t < tiddlers.length; t++) {
var date = tiddlers[t].created.formatString("YYYY0MM0DD")
if (!createds[date])
createds[date]=new Array();
createds[date].push(tiddlers[t].title);
}
return createds;
}
function hasCreateds(date) // returns true if date has created tiddlers
{
if (!config.macros.date.createds) config.macros.date.createds=indexCreateds();
return (config.macros.date.createds[date.formatString("YYYY0MM0DD")]!=undefined);
}
function addCreatedsToPopup(popup,when,format)
{
var force=(store.isDirty() && when.formatString("YYYY0MM0DD")==new Date().formatString("YYYY0MM0DD"));
if (force || !config.macros.date.createds) config.macros.date.createds=indexCreateds();
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var createds = config.macros.date.createds[when.formatString("YYYY0MM0DD")];
if (createds) {
createds.sort();
var e=createTiddlyElement(popup,"div",null,null,"created ("+createds.length+")");
for(var t=0; t<createds.length; t++) {
var link=createTiddlyLink(popup,createds[t],false);
link.appendChild(document.createTextNode(indent+createds[t]));
createTiddlyElement(popup,"br",null,null,null);
}
}
}
//}}}
//{{{
function indexModifieds() // build list of tiddlers, hash indexed by modification date
{
var modifieds= { };
var tiddlers = store.getTiddlers("title","excludeLists");
for (var t = 0; t < tiddlers.length; t++) {
var date = tiddlers[t].modified.formatString("YYYY0MM0DD")
if (!modifieds[date])
modifieds[date]=new Array();
modifieds[date].push(tiddlers[t].title);
}
return modifieds;
}
function hasModifieds(date) // returns true if date has modified tiddlers
{
if (!config.macros.date.modifieds) config.macros.date.modifieds = indexModifieds();
return (config.macros.date.modifieds[date.formatString("YYYY0MM0DD")]!=undefined);
}
function addModifiedsToPopup(popup,when,format)
{
var date=when.formatString("YYYY0MM0DD");
var force=(store.isDirty() && date==new Date().formatString("YYYY0MM0DD"));
if (force || !config.macros.date.modifieds) config.macros.date.modifieds=indexModifieds();
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var mods = config.macros.date.modifieds[date];
if (mods) {
// if a tiddler was created on this date, don't list it in the 'changed' section
if (config.macros.date.createds && config.macros.date.createds[date]) {
var temp=[];
for(var t=0; t<mods.length; t++)
if (!config.macros.date.createds[date].contains(mods[t]))
temp.push(mods[t]);
mods=temp;
}
mods.sort();
var e=createTiddlyElement(popup,"div",null,null,"changed ("+mods.length+")");
for(var t=0; t<mods.length; t++) {
var link=createTiddlyLink(popup,mods[t],false);
link.appendChild(document.createTextNode(indent+mods[t]));
createTiddlyElement(popup,"br",null,null,null);
}
}
}
//}}}
//{{{
function hasTagged(date,format) // returns true if date is tagging other tiddlers
{
return store.getTaggedTiddlers(date.formatString(format)).length>0;
}
function addTaggedToPopup(popup,when,format)
{
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var tagged=store.getTaggedTiddlers(when.formatString(format));
if (tagged.length) var e=createTiddlyElement(popup,"div",null,null,"tagged ("+tagged.length+")");
for(var t=0; t<tagged.length; t++) {
var link=createTiddlyLink(popup,tagged[t].title,false);
link.appendChild(document.createTextNode(indent+tagged[t].title));
createTiddlyElement(popup,"br",null,null,null);
}
}
//}}}
//{{{
function indexReminders(date,leadtime) // build list of tiddlers with reminders, hash indexed by reminder date
{
var reminders = { };
if(window.findTiddlersWithReminders!=undefined) { // reminder plugin is installed
// DEBUG var starttime=new Date();
var t = findTiddlersWithReminders(date, [0,leadtime], null, null, 1);
for(var i=0; i<t.length; i++) reminders[t[i].matchedDate]=true;
// DEBUG var out="Found "+t.length+" reminders in "+((new Date())-starttime+1)+"ms\n";
// DEBUG out+="startdate: "+date.toLocaleDateString()+"\n"+"leadtime: "+leadtime+" days\n\n";
// DEBUG for(var i=0; i<t.length; i++) { out+=t[i].matchedDate.toLocaleDateString()+" "+t[i].params.title+"\n"; }
// DEBUG alert(out);
}
return reminders;
}
function hasReminders(date) // returns true if date has reminders
{
if (window.reminderCacheForCalendar)
return window.reminderCacheForCalendar[date]; // use calendar cache
if (!config.macros.date.reminders)
config.macros.date.reminders = indexReminders(date,90); // create a 90-day leadtime reminder cache
return (config.macros.date.reminders[date]);
}
function addRemindersToPopup(popup,when,format)
{
if(window.findTiddlersWithReminders==undefined) return; // reminder plugin not installed
var indent = String.fromCharCode(160)+String.fromCharCode(160);
var reminders=findTiddlersWithReminders(when, [0,31],null,null,1);
createTiddlyElement(popup,"div",null,null,"reminders ("+(reminders.length||"none")+")");
for(var t=0; t<reminders.length; t++) {
link = createTiddlyLink(popup,reminders[t].tiddler,false);
var diff=reminders[t].diff;
diff=(diff<1)?"Today":((diff==1)?"Tomorrow":diff+" days");
var txt=(reminders[t].params["title"])?reminders[t].params["title"]:reminders[t].tiddler;
link.appendChild(document.createTextNode(indent+diff+" - "+txt));
createTiddlyElement(popup,"br",null,null,null);
}
if (readOnly) return; // omit "new reminder..." link
var link = createTiddlyLink(popup,indent+"new reminder...",true); createTiddlyElement(popup,"br");
var title = when.formatString(format);
link.title="add a reminder to '"+title+"'";
link.onclick = function() {
// show tiddler editor
story.displayTiddler(null, title, 2, null, null, false, false);
// find body 'textarea'
var c =document.getElementById("tiddler" + title).getElementsByTagName("*");
for (var i=0; i<c.length; i++) if ((c[i].tagName.toLowerCase()=="textarea") && (c[i].getAttribute("edit")=="text")) break;
// append reminder macro to tiddler content
if (i<c.length) {
if (store.tiddlerExists(title)) c[i].value+="\n"; else c[i].value="";
c[i].value += "<<reminder";
c[i].value += " day:"+when.getDate();
c[i].value += " month:"+(when.getMonth()+1);
c[i].value += " year:"+when.getFullYear();
c[i].value += ' title:"Enter a title" >>';
}
};
}
//}}}
/***
|Name|DatePluginConfig|
|Source|http://www.TiddlyTools.com/#DatePluginConfig|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.6.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|formats, background colors and other optional settings for DatePlugin|
***/
// // Default popup content display options (can be overridden by cookies)
//{{{
if (config.options.chkDatePopupHideCreated===undefined)
config.options.chkDatePopupHideCreated=false;
if (config.options.chkDatePopupHideChanged===undefined)
config.options.chkDatePopupHideChanged=false;
if (config.options.chkDatePopupHideTagged===undefined)
config.options.chkDatePopupHideTagged=false;
if (config.options.chkDatePopupHideReminders===undefined)
config.options.chkDatePopupHideReminders=false;
//}}}
// // show Julian date number below regular date
//{{{
if (config.options.chkShowJulianDate===undefined)
config.options.chkShowJulianDate=false;
//}}}
// // fixed-date annual holidays
//{{{
config.macros.date.holidays=[
"01/01", // NewYearsDay,
"07/04", // US Independence Day
"07/24" // Eric's Birthday (hooray!)
];
//}}}
// // weekend map (1=weekend, 0=weekday)
//{{{
config.macros.date.weekend=[ 1,0,0,0,0,0,1 ]; // day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6
//}}}
// // date display/link formats
//{{{
config.macros.date.format="YYYY.0MM.0DD"; // default date display format
config.macros.date.linkformat="YYYY.0MM.0DD"; // 'dated tiddler' link format
//}}}
// // When displaying a calendar (see [[CalendarPlugin]]), you can customize the colors/styles that are applied to the calendar dates by modifying the values and/or functions below:
//{{{
// default calendar colors
config.macros.date.weekendbg="#c0c0c0";
config.macros.date.holidaybg="#ffaace";
config.macros.date.createdbg="#bbeeff";
config.macros.date.modifiedsbg="#bbeeff";
config.macros.date.linkedbg="#babb1e";
config.macros.date.remindersbg="#c0ffee";
// apply calendar styles
function setDateStyle(place,link,weekend) {
// alias variable names for code readability
var date=link.date;
var fmt=link.linkformat;
var linkto=date.formatString(fmt);
var cmd=config.macros.date;
if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=""))
{ place.style.background = cmd.weekendbg; }
if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
{ link.style.fontStyle="normal"; link.style.fontWeight="bold"; }
if (hasReminders(date))
{ link.style.textDecoration="underline"; }
if (isToday(date))
{ link.style.border="1px solid black"; }
if (isHoliday(date)&&(cmd.holidaybg!=""))
{ place.style.background = cmd.holidaybg; }
if (hasCreateds(date)&&(cmd.createdbg!=""))
{ place.style.background = cmd.createdbg; }
if (hasModifieds(date)&&(cmd.modifiedsbg!=""))
{ place.style.background = cmd.modifiedsbg; }
if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=""))
{ place.style.background = cmd.linkedbg; }
if (hasReminders(date)&&(cmd.remindersbg!=""))
{ place.style.background = cmd.remindersbg; }
if (isToday(date)&&(cmd.todaybg!=""))
{ place.style.background = cmd.todaybg; }
if (config.options.chkShowJulianDate) {
var m=[0,31,59,90,120,151,181,212,243,273,304,334];
var d=date.getDate()+m[date.getMonth()];
var y=date.getFullYear();
if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0) d++; // after February in a leap year
wikify("@@font-size:80%;<br>"+d+"@@",place);
}
}
//}}}
<!--{{{-->
<!--
▐▀
1. Added a custom field «orderingkey» for ordering tiddlers tagged «ordered»
2. Removed QuickEditToolbar - don't want to install QuickEditPlugin
▄▌
-->
<!--
|Name|EditTemplate|
|Source|http://www.TiddlyTools.com/#EditTemplate|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|template|
|Requires|ToolbarCommands|
|Overrides||
|Description|custom version of shadow template used to display tiddler for normal editing|
-->
<span class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></span>
<div class='title' macro='view title'></div>
<div style='clear:both'></div>
<div class='editor' macro='edit title'></div>
<!--<div macro='tiddler QuickEditToolbar'></div>-->
<div class='editor' macro='edit text'></div>
<span macro='resizeEditor'></span><span macro='setUserName'></span>
<div class='editor' macro='preview hide text'></div>
<div class='editor' macro='edit tags'></div>
<!--▐▀(1)-->
<div macro="showWhenTaggedAny ordered fav" style='margin-top:2px'>
<span class='editorFooter' macro='message views.editor.orderKeyPrompt' style='float:left'></span>
<span class='editor' macro='edit orderingkey'
style='text-align:right;float:left;width:2em;margin-left:.3em;margin-right:1em;'></span>
</div>
<!--(1)▄▌-->
<div class='toolbar editorFooter' style='text-align:left !important;float:left !important'>
<span macro='message views.editor.tagPrompt'></span>
<span macro='tagChooser'></span>
</div>
<div style='clear:both'></div>
<!--}}}-->
/***
|Name:|ExtentTagButtonPlugin|
|Description:|Adds a New tiddler button in the tag drop down|
|Version:|3.2 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#ExtendTagButtonPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
window.onClickTag_mptw_orig = window.onClickTag;
window.onClickTag = function(e) {
window.onClickTag_mptw_orig.apply(this,arguments);
var tag = this.getAttribute("tag");
var title = this.getAttribute("tiddler");
// Thanks Saq, you're a genius :)
var popup = Popup.stack[Popup.stack.length-1].popup;
createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
wikify("<<newTiddler label:'New tiddler' tag:'"+tag+"'>>",createTiddlyElement(popup,"li"));
return false;
}
//}}}
/***
|''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
// %/
/***
|''Name:''|ForEachTiddlerPlugin|
|''Version:''|1.0.8 (2007-04-12)|
|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''Copyright:''|© 2005-2007 [[abego Software|http://www.abego-software.de]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
!Description
Create customizable lists, tables etc. for your selections of tiddlers. Specify the tiddlers to include and their order through a powerful language.
''Syntax:''
|>|{{{<<}}}''forEachTiddler'' [''in'' //tiddlyWikiPath//] [''where'' //whereCondition//] [''sortBy'' //sortExpression// [''ascending'' //or// ''descending'']] [''script'' //scriptText//] [//action// [//actionParameters//]]{{{>>}}}|
|//tiddlyWikiPath//|The filepath to the TiddlyWiki the macro should work on. When missing the current TiddlyWiki is used.|
|//whereCondition//|(quoted) JavaScript boolean expression. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|
|//sortExpression//|(quoted) JavaScript expression returning "comparable" objects (using '{{{<}}}','{{{>}}}','{{{==}}}'. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|
|//scriptText//|(quoted) JavaScript text. Typically defines JavaScript functions that are called by the various JavaScript expressions (whereClause, sortClause, action arguments,...)|
|//action//|The action that should be performed on every selected tiddler, in the given order. By default the actions [[addToList|AddToListAction]] and [[write|WriteAction]] are supported. When no action is specified [[addToList|AddToListAction]] is used.|
|//actionParameters//|(action specific) parameters the action may refer while processing the tiddlers (see action descriptions for details). <<tiddler [[JavaScript in actionParameters]]>>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
See details see [[ForEachTiddlerMacro]] and [[ForEachTiddlerExamples]].
!Revision history
* v1.0.8 (2007-04-12)
** Adapted to latest TiddlyWiki 2.2 Beta importTiddlyWiki API (introduced with changeset 2004). TiddlyWiki 2.2 Beta builds prior to changeset 2004 are no longer supported (but TiddlyWiki 2.1 and earlier, of cause)
* v1.0.7 (2007-03-28)
** Also support "pre" formatted TiddlyWikis (introduced with TW 2.2) (when using "in" clause to work on external tiddlers)
* v1.0.6 (2006-09-16)
** Context provides "viewerTiddler", i.e. the tiddler used to view the macro. Most times this is equal to the "inTiddler", but when using the "tiddler" macro both may be different.
** Support "begin", "end" and "none" expressions in "write" action
* v1.0.5 (2006-02-05)
** Pass tiddler containing the macro with wikify, context object also holds reference to tiddler containing the macro ("inTiddler"). Thanks to SimonBaird.
** Support Firefox 1.5.0.1
** Internal
*** Make "JSLint" conform
*** "Only install once"
* v1.0.4 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.3 (2005-12-22)
** Features:
*** Write output to a file supports multi-byte environments (Thanks to Bram Chen)
*** Provide API to access the forEachTiddler functionality directly through JavaScript (see getTiddlers and performMacro)
** Enhancements:
*** Improved error messages on InternetExplorer.
* v1.0.2 (2005-12-10)
** Features:
*** context object also holds reference to store (TiddlyWiki)
** Fixed Bugs:
*** ForEachTiddler 1.0.1 has broken support on win32 Opera 8.51 (Thanks to BrunoSabin for reporting)
* v1.0.1 (2005-12-08)
** Features:
*** Access tiddlers stored in separated TiddlyWikis through the "in" option. I.e. you are no longer limited to only work on the "current TiddlyWiki".
*** Write output to an external file using the "toFile" option of the "write" action. With this option you may write your customized tiddler exports.
*** Use the "script" section to define "helper" JavaScript functions etc. to be used in the various JavaScript expressions (whereClause, sortClause, action arguments,...).
*** Access and store context information for the current forEachTiddler invocation (through the build-in "context" object) .
*** Improved script evaluation (for where/sort clause and write scripts).
* v1.0.0 (2005-11-20)
** initial version
!Code
***/
//{{{
//============================================================================
//============================================================================
// ForEachTiddlerPlugin
//============================================================================
//============================================================================
// Only install once
if (!version.extensions.ForEachTiddlerPlugin) {
if (!window.abego) window.abego = {};
version.extensions.ForEachTiddlerPlugin = {
major: 1, minor: 0, revision: 8,
date: new Date(2007,3,12),
source: "http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin",
licence: "[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]",
copyright: "Copyright (c) abego Software GmbH, 2005-2007 (www.abego-software.de)"
};
// For backward compatibility with TW 1.2.x
//
if (!TiddlyWiki.prototype.forEachTiddler) {
TiddlyWiki.prototype.forEachTiddler = function(callback) {
for(var t in this.tiddlers) {
callback.call(this,t,this.tiddlers[t]);
}
};
}
//============================================================================
// forEachTiddler Macro
//============================================================================
version.extensions.forEachTiddler = {
major: 1, minor: 0, revision: 8, date: new Date(2007,3,12), provider: "http://tiddlywiki.abego-software.de"};
// ---------------------------------------------------------------------------
// Configurations and constants
// ---------------------------------------------------------------------------
config.macros.forEachTiddler = {
// Standard Properties
label: "forEachTiddler",
prompt: "Perform actions on a (sorted) selection of tiddlers",
// actions
actions: {
addToList: {},
write: {}
}
};
// ---------------------------------------------------------------------------
// The forEachTiddler Macro Handler
// ---------------------------------------------------------------------------
config.macros.forEachTiddler.getContainingTiddler = function(e) {
while(e && !hasClass(e,"tiddler"))
e = e.parentNode;
var title = e ? e.getAttribute("tiddler") : null;
return title ? store.getTiddler(title) : null;
};
config.macros.forEachTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
// config.macros.forEachTiddler.traceMacroCall(place,macroName,params,wikifier,paramString,tiddler);
if (!tiddler) tiddler = config.macros.forEachTiddler.getContainingTiddler(place);
// --- Parsing ------------------------------------------
var i = 0; // index running over the params
// Parse the "in" clause
var tiddlyWikiPath = undefined;
if ((i < params.length) && params[i] == "in") {
i++;
if (i >= params.length) {
this.handleError(place, "TiddlyWiki path expected behind 'in'.");
return;
}
tiddlyWikiPath = this.paramEncode((i < params.length) ? params[i] : "");
i++;
}
// Parse the where clause
var whereClause ="true";
if ((i < params.length) && params[i] == "where") {
i++;
whereClause = this.paramEncode((i < params.length) ? params[i] : "");
i++;
}
// Parse the sort stuff
var sortClause = null;
var sortAscending = true;
if ((i < params.length) && params[i] == "sortBy") {
i++;
if (i >= params.length) {
this.handleError(place, "sortClause missing behind 'sortBy'.");
return;
}
sortClause = this.paramEncode(params[i]);
i++;
if ((i < params.length) && (params[i] == "ascending" || params[i] == "descending")) {
sortAscending = params[i] == "ascending";
i++;
}
}
// Parse the script
var scriptText = null;
if ((i < params.length) && params[i] == "script") {
i++;
scriptText = this.paramEncode((i < params.length) ? params[i] : "");
i++;
}
// Parse the action.
// When we are already at the end use the default action
var actionName = "addToList";
if (i < params.length) {
if (!config.macros.forEachTiddler.actions[params[i]]) {
this.handleError(place, "Unknown action '"+params[i]+"'.");
return;
} else {
actionName = params[i];
i++;
}
}
// Get the action parameter
// (the parsing is done inside the individual action implementation.)
var actionParameter = params.slice(i);
// --- Processing ------------------------------------------
try {
this.performMacro({
place: place,
inTiddler: tiddler,
whereClause: whereClause,
sortClause: sortClause,
sortAscending: sortAscending,
actionName: actionName,
actionParameter: actionParameter,
scriptText: scriptText,
tiddlyWikiPath: tiddlyWikiPath});
} catch (e) {
this.handleError(place, e);
}
};
// Returns an object with properties "tiddlers" and "context".
// tiddlers holds the (sorted) tiddlers selected by the parameter,
// context the context of the execution of the macro.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlersAndContext = function(parameter) {
var context = config.macros.forEachTiddler.createContext(parameter.place, parameter.whereClause, parameter.sortClause, parameter.sortAscending, parameter.actionName, parameter.actionParameter, parameter.scriptText, parameter.tiddlyWikiPath, parameter.inTiddler);
var tiddlyWiki = parameter.tiddlyWikiPath ? this.loadTiddlyWiki(parameter.tiddlyWikiPath) : store;
context["tiddlyWiki"] = tiddlyWiki;
// Get the tiddlers, as defined by the whereClause
var tiddlers = this.findTiddlers(parameter.whereClause, context, tiddlyWiki);
context["tiddlers"] = tiddlers;
// Sort the tiddlers, when sorting is required.
if (parameter.sortClause) {
this.sortTiddlers(tiddlers, parameter.sortClause, parameter.sortAscending, context);
}
return {tiddlers: tiddlers, context: context};
};
// Returns the (sorted) tiddlers selected by the parameter.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlers = function(parameter) {
return this.getTiddlersAndContext(parameter).tiddlers;
};
// Performs the macros with the given parameter.
//
// @param parameter holds the parameter of the macro as separate properties.
// The following properties are supported:
//
// place
// whereClause
// sortClause
// sortAscending
// actionName
// actionParameter
// scriptText
// tiddlyWikiPath
//
// All properties are optional.
// For most actions the place property must be defined.
//
config.macros.forEachTiddler.performMacro = function(parameter) {
var tiddlersAndContext = this.getTiddlersAndContext(parameter);
// Perform the action
var actionName = parameter.actionName ? parameter.actionName : "addToList";
var action = config.macros.forEachTiddler.actions[actionName];
if (!action) {
this.handleError(parameter.place, "Unknown action '"+actionName+"'.");
return;
}
var actionHandler = action.handler;
actionHandler(parameter.place, tiddlersAndContext.tiddlers, parameter.actionParameter, tiddlersAndContext.context);
};
// ---------------------------------------------------------------------------
// The actions
// ---------------------------------------------------------------------------
// Internal.
//
// --- The addToList Action -----------------------------------------------
//
config.macros.forEachTiddler.actions.addToList.handler = function(place, tiddlers, parameter, context) {
// Parse the parameter
var p = 0;
// Check for extra parameters
if (parameter.length > p) {
config.macros.forEachTiddler.createExtraParameterErrorElement(place, "addToList", parameter, p);
return;
}
// Perform the action.
var list = document.createElement("ul");
place.appendChild(list);
for (var i = 0; i < tiddlers.length; i++) {
var tiddler = tiddlers[i];
var listItem = document.createElement("li");
list.appendChild(listItem);
createTiddlyLink(listItem, tiddler.title, true);
}
};
abego.parseNamedParameter = function(name, parameter, i) {
var beginExpression = null;
if ((i < parameter.length) && parameter[i] == name) {
i++;
if (i >= parameter.length) {
throw "Missing text behind '%0'".format([name]);
}
return config.macros.forEachTiddler.paramEncode(parameter[i]);
}
return null;
}
// Internal.
//
// --- The write Action ---------------------------------------------------
//
config.macros.forEachTiddler.actions.write.handler = function(place, tiddlers, parameter, context) {
// Parse the parameter
var p = 0;
if (p >= parameter.length) {
this.handleError(place, "Missing expression behind 'write'.");
return;
}
var textExpression = config.macros.forEachTiddler.paramEncode(parameter[p]);
p++;
// Parse the "begin" option
var beginExpression = abego.parseNamedParameter("begin", parameter, p);
if (beginExpression !== null)
p += 2;
var endExpression = abego.parseNamedParameter("end", parameter, p);
if (endExpression !== null)
p += 2;
var noneExpression = abego.parseNamedParameter("none", parameter, p);
if (noneExpression !== null)
p += 2;
// Parse the "toFile" option
var filename = null;
var lineSeparator = undefined;
if ((p < parameter.length) && parameter[p] == "toFile") {
p++;
if (p >= parameter.length) {
this.handleError(place, "Filename expected behind 'toFile' of 'write' action.");
return;
}
filename = config.macros.forEachTiddler.getLocalPath(config.macros.forEachTiddler.paramEncode(parameter[p]));
p++;
if ((p < parameter.length) && parameter[p] == "withLineSeparator") {
p++;
if (p >= parameter.length) {
this.handleError(place, "Line separator text expected behind 'withLineSeparator' of 'write' action.");
return;
}
lineSeparator = config.macros.forEachTiddler.paramEncode(parameter[p]);
p++;
}
}
// Check for extra parameters
if (parameter.length > p) {
config.macros.forEachTiddler.createExtraParameterErrorElement(place, "write", parameter, p);
return;
}
// Perform the action.
var func = config.macros.forEachTiddler.getEvalTiddlerFunction(textExpression, context);
var count = tiddlers.length;
var text = "";
if (count > 0 && beginExpression)
text += config.macros.forEachTiddler.getEvalTiddlerFunction(beginExpression, context)(undefined, context, count, undefined);
for (var i = 0; i < count; i++) {
var tiddler = tiddlers[i];
text += func(tiddler, context, count, i);
}
if (count > 0 && endExpression)
text += config.macros.forEachTiddler.getEvalTiddlerFunction(endExpression, context)(undefined, context, count, undefined);
if (count == 0 && noneExpression)
text += config.macros.forEachTiddler.getEvalTiddlerFunction(noneExpression, context)(undefined, context, count, undefined);
if (filename) {
if (lineSeparator !== undefined) {
lineSeparator = lineSeparator.replace(/\\n/mg, "\n").replace(/\\r/mg, "\r");
text = text.replace(/\n/mg,lineSeparator);
}
saveFile(filename, convertUnicodeToUTF8(text));
} else {
var wrapper = createTiddlyElement(place, "span");
wikify(text, wrapper, null/* highlightRegExp */, context.inTiddler);
}
};
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
// Internal.
//
config.macros.forEachTiddler.createContext = function(placeParam, whereClauseParam, sortClauseParam, sortAscendingParam, actionNameParam, actionParameterParam, scriptText, tiddlyWikiPathParam, inTiddlerParam) {
return {
place : placeParam,
whereClause : whereClauseParam,
sortClause : sortClauseParam,
sortAscending : sortAscendingParam,
script : scriptText,
actionName : actionNameParam,
actionParameter : actionParameterParam,
tiddlyWikiPath : tiddlyWikiPathParam,
inTiddler : inTiddlerParam, // the tiddler containing the <<forEachTiddler ...>> macro call.
viewerTiddler : config.macros.forEachTiddler.getContainingTiddler(placeParam) // the tiddler showing the forEachTiddler result
};
};
// Internal.
//
// Returns a TiddlyWiki with the tiddlers loaded from the TiddlyWiki of
// the given path.
//
config.macros.forEachTiddler.loadTiddlyWiki = function(path, idPrefix) {
if (!idPrefix) {
idPrefix = "store";
}
var lenPrefix = idPrefix.length;
// Read the content of the given file
var content = loadFile(this.getLocalPath(path));
if(content === null) {
throw "TiddlyWiki '"+path+"' not found.";
}
var tiddlyWiki = new TiddlyWiki();
// Starting with TW 2.2 there is a helper function to import the tiddlers
if (tiddlyWiki.importTiddlyWiki) {
if (!tiddlyWiki.importTiddlyWiki(content))
throw "File '"+path+"' is not a TiddlyWiki.";
tiddlyWiki.dirty = false;
return tiddlyWiki;
}
// The legacy code, for TW < 2.2
// Locate the storeArea div's
var posOpeningDiv = content.indexOf(startSaveArea);
var posClosingDiv = content.lastIndexOf(endSaveArea);
if((posOpeningDiv == -1) || (posClosingDiv == -1)) {
throw "File '"+path+"' is not a TiddlyWiki.";
}
var storageText = content.substr(posOpeningDiv + startSaveArea.length, posClosingDiv);
// Create a "div" element that contains the storage text
var myStorageDiv = document.createElement("div");
myStorageDiv.innerHTML = storageText;
myStorageDiv.normalize();
// Create all tiddlers in a new TiddlyWiki
// (following code is modified copy of TiddlyWiki.prototype.loadFromDiv)
var store = myStorageDiv.childNodes;
for(var t = 0; t < store.length; t++) {
var e = store[t];
var title = null;
if(e.getAttribute)
title = e.getAttribute("tiddler");
if(!title && e.id && e.id.substr(0,lenPrefix) == idPrefix)
title = e.id.substr(lenPrefix);
if(title && title !== "") {
var tiddler = tiddlyWiki.createTiddler(title);
tiddler.loadFromDiv(e,title);
}
}
tiddlyWiki.dirty = false;
return tiddlyWiki;
};
// Internal.
//
// Returns a function that has a function body returning the given javaScriptExpression.
// The function has the parameters:
//
// (tiddler, context, count, index)
//
config.macros.forEachTiddler.getEvalTiddlerFunction = function (javaScriptExpression, context) {
var script = context["script"];
var functionText = "var theFunction = function(tiddler, context, count, index) { return "+javaScriptExpression+"}";
var fullText = (script ? script+";" : "")+functionText+";theFunction;";
return eval(fullText);
};
// Internal.
//
config.macros.forEachTiddler.findTiddlers = function(whereClause, context, tiddlyWiki) {
var result = [];
var func = config.macros.forEachTiddler.getEvalTiddlerFunction(whereClause, context);
tiddlyWiki.forEachTiddler(function(title,tiddler) {
if (func(tiddler, context, undefined, undefined)) {
result.push(tiddler);
}
});
return result;
};
// Internal.
//
config.macros.forEachTiddler.createExtraParameterErrorElement = function(place, actionName, parameter, firstUnusedIndex) {
var message = "Extra parameter behind '"+actionName+"':";
for (var i = firstUnusedIndex; i < parameter.length; i++) {
message += " "+parameter[i];
}
this.handleError(place, message);
};
// Internal.
//
config.macros.forEachTiddler.sortAscending = function(tiddlerA, tiddlerB) {
var result =
(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue)
? 0
: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
? -1
: +1;
return result;
};
// Internal.
//
config.macros.forEachTiddler.sortDescending = function(tiddlerA, tiddlerB) {
var result =
(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue)
? 0
: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
? +1
: -1;
return result;
};
// Internal.
//
config.macros.forEachTiddler.sortTiddlers = function(tiddlers, sortClause, ascending, context) {
// To avoid evaluating the sortClause whenever two items are compared
// we pre-calculate the sortValue for every item in the array and store it in a
// temporary property ("forEachTiddlerSortValue") of the tiddlers.
var func = config.macros.forEachTiddler.getEvalTiddlerFunction(sortClause, context);
var count = tiddlers.length;
var i;
for (i = 0; i < count; i++) {
var tiddler = tiddlers[i];
tiddler.forEachTiddlerSortValue = func(tiddler,context, undefined, undefined);
}
// Do the sorting
tiddlers.sort(ascending ? this.sortAscending : this.sortDescending);
// Delete the temporary property that holds the sortValue.
for (i = 0; i < tiddlers.length; i++) {
delete tiddlers[i].forEachTiddlerSortValue;
}
};
// Internal.
//
config.macros.forEachTiddler.trace = function(message) {
displayMessage(message);
};
// Internal.
//
config.macros.forEachTiddler.traceMacroCall = function(place,macroName,params) {
var message ="<<"+macroName;
for (var i = 0; i < params.length; i++) {
message += " "+params[i];
}
message += ">>";
displayMessage(message);
};
// Internal.
//
// Creates an element that holds an error message
//
config.macros.forEachTiddler.createErrorElement = function(place, exception) {
var message = (exception.description) ? exception.description : exception.toString();
return createTiddlyElement(place,"span",null,"forEachTiddlerError","<<forEachTiddler ...>>: "+message);
};
// Internal.
//
// @param place [may be null]
//
config.macros.forEachTiddler.handleError = function(place, exception) {
if (place) {
this.createErrorElement(place, exception);
} else {
throw exception;
}
};
// Internal.
//
// Encodes the given string.
//
// Replaces
// "$))" to ">>"
// "$)" to ">"
//
config.macros.forEachTiddler.paramEncode = function(s) {
var reGTGT = new RegExp("\\$\\)\\)","mg");
var reGT = new RegExp("\\$\\)","mg");
return s.replace(reGTGT, ">>").replace(reGT, ">");
};
// Internal.
//
// Returns the given original path (that is a file path, starting with "file:")
// as a path to a local file, in the systems native file format.
//
// Location information in the originalPath (i.e. the "#" and stuff following)
// is stripped.
//
config.macros.forEachTiddler.getLocalPath = function(originalPath) {
// Remove any location part of the URL
var hashPos = originalPath.indexOf("#");
if(hashPos != -1)
originalPath = originalPath.substr(0,hashPos);
// Convert to a native file format assuming
// "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
// "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
// "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
// "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
var localPath;
if(originalPath.charAt(9) == ":") // pc local file
localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
else if(originalPath.indexOf("file://///") === 0) // FireFox pc network file
localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
else if(originalPath.indexOf("file:///") === 0) // mac/unix local file
localPath = unescape(originalPath.substr(7));
else if(originalPath.indexOf("file:/") === 0) // mac/unix local file
localPath = unescape(originalPath.substr(5));
else // pc network file
localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
return localPath;
};
// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
".forEachTiddlerError{color: #ffffff;background-color: #880000;}",
"forEachTiddler");
//============================================================================
// End of forEachTiddler Macro
//============================================================================
//============================================================================
// String.startsWith Function
//============================================================================
//
// Returns true if the string starts with the given prefix, false otherwise.
//
version.extensions["String.startsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.startsWith = function(prefix) {
var n = prefix.length;
return (this.length >= n) && (this.slice(0, n) == prefix);
};
//============================================================================
// String.endsWith Function
//============================================================================
//
// Returns true if the string ends with the given suffix, false otherwise.
//
version.extensions["String.endsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.endsWith = function(suffix) {
var n = suffix.length;
return (this.length >= n) && (this.right(n) == suffix);
};
//============================================================================
// String.contains Function
//============================================================================
//
// Returns true when the string contains the given substring, false otherwise.
//
version.extensions["String.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.contains = function(substring) {
return this.indexOf(substring) >= 0;
};
//============================================================================
// Array.indexOf Function
//============================================================================
//
// Returns the index of the first occurance of the given item in the array or
// -1 when no such item exists.
//
// @param item [may be null]
//
version.extensions["Array.indexOf"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.indexOf = function(item) {
for (var i = 0; i < this.length; i++) {
if (this[i] == item) {
return i;
}
}
return -1;
};
//============================================================================
// Array.contains Function
//============================================================================
//
// Returns true when the array contains the given item, otherwise false.
//
// @param item [may be null]
//
version.extensions["Array.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.contains = function(item) {
return (this.indexOf(item) >= 0);
};
//============================================================================
// Array.containsAny Function
//============================================================================
//
// Returns true when the array contains at least one of the elements
// of the item. Otherwise (or when items contains no elements) false is returned.
//
version.extensions["Array.containsAny"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAny = function(items) {
for(var i = 0; i < items.length; i++) {
if (this.contains(items[i])) {
return true;
}
}
return false;
};
//============================================================================
// Array.containsAll Function
//============================================================================
//
// Returns true when the array contains all the items, otherwise false.
//
// When items is null false is returned (even if the array contains a null).
//
// @param items [may be null]
//
version.extensions["Array.containsAll"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAll = function(items) {
for(var i = 0; i < items.length; i++) {
if (!this.contains(items[i])) {
return false;
}
}
return true;
};
} // of "install only once"
// Used Globals (for JSLint) ==============
// ... DOM
/*global document */
// ... TiddlyWiki Core
/*global convertUnicodeToUTF8, createTiddlyElement, createTiddlyLink,
displayMessage, endSaveArea, hasClass, loadFile, saveFile,
startSaveArea, store, wikify */
//}}}
/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
/***
|Name|FullScreenPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#FullScreenPlugin|
|Version|1.1|
|Requires|~TW2.x|
!Description:
Toggle between viewing tiddlers fullscreen and normally. Very handy for when you need more viewing space.
!Demo:
Click the ↕ button in the toolbar for this tiddler. Click it again to turn off fullscreen.
!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Edit the ViewTemplate to add the fullscreen command to the toolbar.
!History:
*25-07-06: ver 1.1
*20-07-06: ver 1.0
!Code
***/
//{{{
var lewcidFullScreen = false;
config.commands.fullscreen =
{
text:" ↕ ",
tooltip:"Fullscreen mode"
};
config.commands.fullscreen.handler = function (event,src,title)
{
if (lewcidFullScreen == false)
{
lewcidFullScreen = true;
setStylesheet('#sidebar, .header, #mainMenu{display:none;} #displayArea{margin:0em 0 0 0 !important;}',"lewcidFullScreenStyle");
}
else
{
lewcidFullScreen = false;
setStylesheet(' ',"lewcidFullScreenStyle");
}
}
config.macros.fullscreen={};
config.macros.fullscreen.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
var label = params[0]||" ↕ ";
var tooltip = params[1]||"Fullscreen mode";
createTiddlyButton(place,label,tooltip,config.commands.fullscreen.handler);
}
var lewcid_fullscreen_closeTiddler = Story.prototype.closeTiddler;
Story.prototype.closeTiddler =function(title,animate,slowly)
{
lewcid_fullscreen_closeTiddler.apply(this,arguments);
if (story.isEmpty() && lewcidFullScreen == true)
config.commands.fullscreen.handler();
}
Slider.prototype.lewcidStop = Slider.prototype.stop;
Slider.prototype.stop = function()
{
this.lewcidStop();
if (story.isEmpty() && lewcidFullScreen == true)
config.commands.fullscreen.handler();
}
//}}}
|''URL:''|http://gimcrackd.com/etc/src/|
|''Description:''|Gimcrack'd: Code and Other Oddments|
|''Author:''|ChrisKlimas|
/***
|Name|GotoPlugin|
|Source|http://www.TiddlyTools.com/#GotoPlugin|
|Documentation|http://www.TiddlyTools.com/#GotoPluginInfo|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|view any tiddler by entering it's title - displays list of possible matches|
''View a tiddler by typing its title and pressing //enter//.'' As you type, a list of possible matches is displayed. You can scroll-and-click (or use arrows+enter) to select/view a tiddler, or press //escape// to close the listbox to resume typing. When the listbox is ''//not//'' being displayed, press //escape// to clear the current text input and start over.
!!!!!Documentation
>see [[GotoPluginInfo]]
!!!!!Revisions
<<<
2008.12.15 [1.7.1] up arrow from input field now moves to end of droplist (search for input). Also, shift+enter cam now be used to quickly invoke search for text.
|please see [[GotoPluginInfo]] for additional revision details|
2006.05.05 [0.0.0] started
<<<
!!!!!Code
***/
//{{{
version.extensions.GotoPlugin= {major: 1, minor: 7, revision: 1, date: new Date(2008,12,15)};
// automatically tweak shadow SideBarOptions to add <<gotoTiddler>> macro above <<search>>
config.shadowTiddlers.SideBarOptions=config.shadowTiddlers.SideBarOptions.replace(/<<search>>/,"{{button{goto}}}\n<<gotoTiddler>><<search>>");
config.macros.gotoTiddler= {
listMaxSize: 10,
listHeading: 'Found %0 matching title%1...',
searchItem: "Search for '%0'...",
handler:
function(place,macroName,params,wikifier,paramString,tiddler) {
var quiet =params.contains("quiet");
var search =params.contains("search");
params = paramString.parseParams("anon",null,true,false,false);
var instyle =getParam(params,"inputstyle","");
var liststyle =getParam(params,"liststyle","");
var filter =getParam(params,"filter","");
var html=this.html;
var keyevent=window.event?"onkeydown":"onkeypress"; // IE event fixup for ESC handling
html=html.replace(/%keyevent%/g,keyevent);
html=html.replace(/%search%/g,search);
html=html.replace(/%quiet%/g,quiet);
html=html.replace(/%instyle%/g,instyle);
html=html.replace(/%liststyle%/g,liststyle);
html=html.replace(/%filter%/g,filter);
if (config.browser.isIE) html=this.IEtableFixup.format([html]);
createTiddlyElement(place,"span").innerHTML=html;
},
html:
'<form onsubmit="return false" style="display:inline;margin:0;padding:0">\
<input name=gotoTiddler type=text autocomplete="off" accesskey="G" style="%instyle%"\
title="Enter title text... ENTER=goto, SHIFT-ENTER=search for text, DOWN=select from list"\
onclick="this.form.list.style.display=\'none\';"\
onfocus="this.select(); this.setAttribute(\'accesskey\',\'G\');"\
%keyevent%="return config.macros.gotoTiddler.inputEscKeyHandler(event,this,this.form.list);"\
onkeyup="return config.macros.gotoTiddler.inputKeyHandler(event,this,%quiet%,%search%);">\
<select name=list style="%liststyle%;display:none;position:absolute"\
onchange="if (!this.selectedIndex) this.selectedIndex=1;"\
onblur="this.style.display=\'none\';"\
%keyevent%="return config.macros.gotoTiddler.selectKeyHandler(event,this,this.form.gotoTiddler);"\
onclick="return config.macros.gotoTiddler.processItem(this.value,this.form.gotoTiddler,this);">\
</select><input name="filter" type="hidden" value="%filter%">\
</form>',
IEtableFixup:
"<table style='width:100%;display:inline;padding:0;margin:0;border:0;'>\
<tr style='padding:0;margin:0;border:0;'><td style='padding:0;margin:0;border:0;'>\
%0</td></tr></table>",
getItems:
function(val,filter) {
if (!this.items.length || val.length<2) { // starting new search, refresh cached list of tiddlers/shadows/tags
this.items=new Array();
if (filter.length) {
var fn=store.getMatchingTiddlers||store.getTaggedTiddlers;
var tiddlers=store.sortTiddlers(fn.apply(store,[filter]),'title');
} else
var tiddlers=store.getTiddlers("title","excludeLists");
for(var t=0; t<tiddlers.length; t++) this.items.push(tiddlers[t].title);
if (!filter.length) {
for (var t in config.shadowTiddlers) this.items.pushUnique(t);
var tags=store.getTags();
for(var t=0; t<tags.length; t++) this.items.pushUnique(tags[t][0]);
}
}
var found = [];
var match=val.toLowerCase();
for(var i=0; i<this.items.length; i++)
if (this.items[i].toLowerCase().indexOf(match)!=-1) found.push(this.items[i]);
return found;
},
items: [], // cached list of tiddlers/shadows/tags
getItemSuffix:
function(t) {
if (store.tiddlerExists(t)) return ""; // tiddler
if (store.isShadowTiddler(t)) return " (shadow)"; // shadow
return " (tag)"; // tag
},
keyProcessed:
function(ev) { // utility function: exits handler and prevents browser from processing the keystroke
ev.cancelBubble=true; // IE4+
try{event.keyCode=0;}catch(e){}; // IE5
if (window.event) ev.returnValue=false; // IE6
if (ev.preventDefault) ev.preventDefault(); // moz/opera/konqueror
if (ev.stopPropagation) ev.stopPropagation(); // all
return false;
},
inputEscKeyHandler:
function(event,here,list) {
var key=event.keyCode;
// escape... hide list (2nd esc=clears input)
if (key==27) {
if (list.style.display=="none")
here.value=here.defaultValue;
list.style.display="none";
return this.keyProcessed(event);
}
return true; // key bubbles up
},
inputKeyHandler:
function(event,here,quiet,search) {
var key=event.keyCode;
var list=here.form.list;
var filter=here.form.filter;
// non-printing chars bubble up, except for a few:
if (key<48) switch(key) {
// backspace=8, enter=13, space=32, up=38, down=40, delete=46
case 8: case 13: case 32: case 38: case 40: case 46: break; default: return true;
}
// blank input... if down/enter... fall through (list all)... else, and hide list
if (!here.value.length && !(key==40 || key==13))
{ list.style.display="none"; return this.keyProcessed(event); }
// make sure list is shown (unless quiet option)
list.style.display=!quiet?"block":"none";
// non-blank input... enter=show/create tiddler, SHIFT-enter=search for text
if (key==13) return this.processItem(event.shiftKey?'*':here.value,here,list);
// up or down key... shows and moves to list...
if (key==38 || key==40) { list.style.display="block"; list.focus(); }
// if list is showing, fill it with found results...
if (list.style.display!="none") {
var indent='\xa0\xa0\xa0';
var found = this.getItems(here.value,filter.value); // find matching items...
found.sort(); // alpha by title
while (list.length > 0) list.options[0]=null; // clear list
var hdr=this.listHeading.format([found.length,found.length==1?"":"s"]);
list.options[0]=new Option(hdr,"",false,false);
for (var t=0; t<found.length; t++) list.options[list.length]=
new Option(indent+found[t]+this.getItemSuffix(found[t]),found[t],false,false);
if (search)
list.options[list.length]=new Option(this.searchItem.format([here.value]),"*",false,false);
list.size=(list.length<this.listMaxSize?list.length:this.listMaxSize); // resize list...
list.selectedIndex=key==38?list.length-1:key==40?1:0;
}
return true; // key bubbles up
},
selectKeyHandler:
function(event,list,editfield) {
if (event.keyCode==27) // escape... hide list, move to edit field
{ editfield.focus(); list.style.display="none"; return this.keyProcessed(event); }
if (event.keyCode==13 && list.value.length) // enter... view selected item
{ this.processItem(list.value,editfield,list); return this.keyProcessed(event); }
return true; // key bubbles up
},
processItem:
function(title,here,list) {
if (!title.length) return;
list.style.display='none';
if (title=="*") { story.search(here.value); return false; } // do full-text search
here.value=title;
story.displayTiddler(null,title); // show selected tiddler
return false;
}
}
//}}}
This ~TiddlyWiki (referred to as "document") is posted for the purpose of criticism and comment. It contains plugins (written by other people) that have been modified to suit the needs of the author of the document (referred to as "me", "I"). Where possible, I was trying to get the author of a plugin to modify it for me (by pointing out bugs or making feature requests via [[TiddlyWiki Google Group|http://groups.google.com/group/TiddlyWiki]]), however there are a few places where I had to change the plugins directly and/or hijack their functions. I tried to clearly identify and comment such changes.
Should you decide to use this document for a purpose other than criticism or comment, please keep in mind:
* When you experience a problem with this document, please do not seek support from a plugins' author before making sure the problem is not caused by the modifications made by me.
* Most of the modifications I made are cut-paste-and-tweak jobs done without real understanding of what is behind the borrowed code and how it all fits together. Hence read the beginning...
/***
|Name:|HideWhenPlugin|
|Description:|Allows conditional inclusion/exclusion in templates|
|Version:|3.1 ($Rev: 3919 $)|
|Date:|$Date: 2008-03-13 02:03:12 +1000 (Thu, 13 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{
window.hideWhenLastTest = false;
window.removeElementWhen = function(test,place) {
window.hideWhenLastTest = test;
if (test) {
removeChildren(place);
place.parentNode.removeChild(place);
}
};
merge(config.macros,{
hideWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( eval(paramString), place);
}},
showWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !eval(paramString), place);
}},
hideWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAll(params), place);
}},
showWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAll(params), place);
}},
hideWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAny(params), place);
}},
showWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAny(params), place);
}},
hideWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAll(params), place);
}},
showWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAll(params), place);
}},
hideWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0]), place);
}},
showWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !(store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0])), place);
}},
hideWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.title == params[0], place);
}},
showWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.title != params[0], place);
}},
'else': { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !window.hideWhenLastTest, place);
}}
});
//}}}
!!! This document is best viewed with Firefox
IE will not render it as intended. Not tested with other browsers.
!!! This document has StorySaverPlugin
It will remember the tiddlers you have opened/closed and present the same story on the next load.
To go back to DefaultTiddlers close every tiddler and reload the document.
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.4|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2009.02.26 [1.9.4] in $(), handle leading '#' on ID for compatibility with JQuery syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 3, date: new Date(2008,6,11)};
config.formatters.push( {
name: "inlineJavascript",
match: "\\<script",
lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",
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) {
var src=lookaheadMatch[1];
var label=lookaheadMatch[2];
var tip=lookaheadMatch[3];
var key=lookaheadMatch[4];
var show=lookaheadMatch[5];
var code=lookaheadMatch[6];
if (src) { // load a script library
// make script tag, set src, add to body to execute, then remove for cleanup
var script = document.createElement("script"); script.src = src;
document.body.appendChild(script); document.body.removeChild(script);
}
if (code) { // there is script code
if (show) // show inline script code in tiddler output
wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
if (label) { // create a link to an 'onclick' script
// add a link, define click handler, save code in link (pass 'place'), set link attributes
var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
link.code="function _out(place){"+fixup+"\n};_out(this);"
link.tiddler=w.tiddler;
link.onclick=function(){
this.bufferedHTML="";
try{ var r=eval(this.code);
if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
if(this.bufferedHTML.length)
s.innerHTML=this.bufferedHTML;
if((typeof(r)==="string")&&r.length) {
wikify(r,s,null,this.tiddler);
return false;
} else return r!==undefined?r:false;
} catch(e){alert(e.description||e.toString());return false;}
};
link.setAttribute("title",tip||"");
var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
link.setAttribute("href",URIcode);
link.style.cursor="pointer";
if (key) link.accessKey=key.substr(0,1); // single character only
}
else { // run inline script code
var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
var c="function _out(place){"+fixup+"\n};_out(w.output);";
try { var out=eval(c); }
catch(e) { out=e.description?e.description:e.toString(); }
if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
}
}
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
} )
//}}}
// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
if(limit > 0) text = text.substr(0,limit);
var wikifier = new Wikifier(text,formatter,null,tiddler);
return wikifier.wikifyPlain();
}
//}}}
// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
/***
|Name:|InstantTimestampPlugin|
|Description:|A handy way to insert timestamps in your tiddler content|
|Version:|1.0.10 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#InstantTimestampPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
If you enter {ts} in your tiddler content (without the spaces) it will be replaced with a timestamp when you save the tiddler. Full list of formats:
* {ts} or {t} -> timestamp
* {ds} or {d} -> datestamp
* !ts or !t at start of line -> !!timestamp
* !ds or !d at start of line -> !!datestamp
(I added the extra ! since that's how I like it. Remove it from translations below if required)
!!Notes
* Change the timeFormat and dateFormat below to suit your preference.
* See also http://mptw2.tiddlyspot.com/#AutoCorrectPlugin
* You could invent other translations and add them to the translations array below.
***/
//{{{
config.InstantTimestamp = {
// adjust to suit
timeFormat: 'DD/0MM/YY 0hh:0mm',
dateFormat: 'DD/0MM/YY',
translations: [
[/^!ts?$/img, "'!!{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
[/^!ds?$/img, "'!!{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"],
// thanks Adapted Cat
[/\{ts?\}(?!\}\})/ig,"'{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
[/\{ds?\}(?!\}\})/ig,"'{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"]
],
excludeTags: [
"noAutoCorrect",
"noTimestamp",
"html",
"CSS",
"css",
"systemConfig",
"systemConfigDisabled",
"zsystemConfig",
"Plugins",
"Plugin",
"plugins",
"plugin",
"javascript",
"code",
"systemTheme",
"systemPalette"
],
excludeTiddlers: [
"StyleSheet",
"StyleSheetLayout",
"StyleSheetColors",
"StyleSheetPrint"
// more?
]
};
TiddlyWiki.prototype.saveTiddler_mptw_instanttimestamp = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created) {
tags = tags ? tags : []; // just in case tags is null
tags = (typeof(tags) == "string") ? tags.readBracketedList() : tags;
var conf = config.InstantTimestamp;
if ( !tags.containsAny(conf.excludeTags) && !conf.excludeTiddlers.contains(newTitle) ) {
var now = new Date();
var trans = conf.translations;
for (var i=0;i<trans.length;i++) {
newBody = newBody.replace(trans[i][0], eval(trans[i][1]));
}
}
// TODO: use apply() instead of naming all args?
return this.saveTiddler_mptw_instanttimestamp(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created);
}
// you can override these in StyleSheet
setStylesheet(".ts,.ds { font-style:italic; }","instantTimestampStyles");
//}}}
/***
|''Name:''|IntelliTaggerPlugin|
|''Version:''|1.0.2 (2007-07-25)|
|''Type:''|plugin|
|''Source:''|http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin|
|''Author:''|Udo Borkowski (ub [at] abego-software [dot] de)|
|''Documentation:''|[[IntelliTaggerPlugin Documentation]]|
|''~SourceCode:''|[[IntelliTaggerPlugin SourceCode]]|
|''Licence:''|[[BSD open source license (abego Software)]]|
|''~CoreVersion:''|2.0.8|
|''Browser:''|Firefox 1.5.0.2 or better|
***/
/***
!Version History
* 1.0.2 (2007-07-25):
** Feature: "Return" key may be used to accept first tag suggestion (beside "Alt-1")
** Bugfix: Keyboard shortcuts (Alt+3 etc.) shifted
* 1.0.1 (2007-05-18): Improvement: Speedup when using TiddlyWikis with many tags
* 1.0.0 (2006-04-26): Initial release
***/
// /%
if(!version.extensions.IntelliTaggerPlugin){if(!window.abego){window.abego={};}if(!abego.internal){abego.internal={};}abego.alertAndThrow=function(s){alert(s);throw s;};if(version.major<2){abego.alertAndThrow("Use TiddlyWiki 2.0.8 or better to run the IntelliTagger Plugin.");}version.extensions.IntelliTaggerPlugin={major:1,minor:0,revision:2,date:new Date(2007,6,25),type:"plugin",source:"http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin",documentation:"[[IntelliTaggerPlugin Documentation]]",sourcecode:"[[IntelliTaggerPlugin SourceCode]]",author:"Udo Borkowski (ub [at] abego-software [dot] de)",licence:"[[BSD open source license (abego Software)]]",tiddlywiki:"Version 2.0.8 or better",browser:"Firefox 1.5.0.2 or better"};abego.createEllipsis=function(_2){var e=createTiddlyElement(_2,"span");e.innerHTML="…";};abego.isPopupOpen=function(_4){return _4&&_4.parentNode==document.body;};abego.openAsPopup=function(_5){if(_5.parentNode!=document.body){document.body.appendChild(_5);}};abego.closePopup=function(_6){if(abego.isPopupOpen(_6)){document.body.removeChild(_6);}};abego.getWindowRect=function(){return {left:findScrollX(),top:findScrollY(),height:findWindowHeight(),width:findWindowWidth()};};abego.moveElement=function(_7,_8,_9){_7.style.left=_8+"px";_7.style.top=_9+"px";};abego.centerOnWindow=function(_a){if(_a.style.position!="absolute"){throw "abego.centerOnWindow: element must have absolute position";}var _b=abego.getWindowRect();abego.moveElement(_a,_b.left+(_b.width-_a.offsetWidth)/2,_b.top+(_b.height-_a.offsetHeight)/2);};abego.isDescendantOrSelf=function(_c,e){while(e){if(_c==e){return true;}e=e.parentNode;}return false;};abego.toSet=function(_e){var _f={};for(var i=0;i<_e.length;i++){_f[_e[i]]=true;}return _f;};abego.filterStrings=function(_11,_12,_13){var _14=[];for(var i=0;i<_11.length&&(_13===undefined||_14.length<_13);i++){var s=_11[i];if(s.match(_12)){_14.push(s);}}return _14;};abego.arraysAreEqual=function(a,b){if(!a){return !b;}if(!b){return false;}var n=a.length;if(n!=b.length){return false;}for(var i=0;i<n;i++){if(a[i]!=b[i]){return false;}}return true;};abego.moveBelowAndClip=function(_1b,_1c){if(!_1c){return;}var _1d=findPosX(_1c);var _1e=findPosY(_1c);var _1f=_1c.offsetHeight;var _20=_1d;var _21=_1e+_1f;var _22=findWindowWidth();if(_22<_1b.offsetWidth){_1b.style.width=(_22-100)+"px";}var _23=_1b.offsetWidth;if(_20+_23>_22){_20=_22-_23-30;}if(_20<0){_20=0;}_1b.style.left=_20+"px";_1b.style.top=_21+"px";_1b.style.display="block";};abego.compareStrings=function(a,b){return (a==b)?0:(a<b)?-1:1;};abego.sortIgnoreCase=function(arr){var _27=[];var n=arr.length;for(var i=0;i<n;i++){var s=arr[i];_27.push([s.toString().toLowerCase(),s]);}_27.sort(function(a,b){return (a[0]==b[0])?0:(a[0]<b[0])?-1:1;});for(i=0;i<n;i++){arr[i]=_27[i][1];}};abego.getTiddlerField=function(_2d,_2e,_2f){var _30=document.getElementById(_2d.idPrefix+_2e);var e=null;if(_30!=null){var _32=_30.getElementsByTagName("*");for(var t=0;t<_32.length;t++){var c=_32[t];if(c.tagName.toLowerCase()=="input"||c.tagName.toLowerCase()=="textarea"){if(!e){e=c;}if(c.getAttribute("edit")==_2f){e=c;}}}}return e;};abego.setRange=function(_35,_36,end){if(_35.setSelectionRange){_35.setSelectionRange(_36,end);var max=0+_35.scrollHeight;var len=_35.textLength;var top=max*_36/len,bot=max*end/len;_35.scrollTop=Math.min(top,(bot+top-_35.clientHeight)/2);}else{if(_35.createTextRange!=undefined){var _3b=_35.createTextRange();_3b.collapse();_3b.moveEnd("character",end);_3b.moveStart("character",_36);_3b.select();}else{_35.select();}}};abego.internal.TagManager=function(){var _3c=null;var _3d=function(){if(_3c){return;}_3c={};store.forEachTiddler(function(_3e,_3f){for(var i=0;i<_3f.tags.length;i++){var tag=_3f.tags[i];var _42=_3c[tag];if(!_42){_42=_3c[tag]={count:0,tiddlers:{}};}_42.tiddlers[_3f.title]=true;_42.count+=1;}});};var _43=TiddlyWiki.prototype.saveTiddler;TiddlyWiki.prototype.saveTiddler=function(_44,_45,_46,_47,_48,_49){var _4a=this.fetchTiddler(_44);var _4b=_4a?_4a.tags:[];var _4c=(typeof _49=="string")?_49.readBracketedList():_49;_43.apply(this,arguments);if(!abego.arraysAreEqual(_4b,_4c)){abego.internal.getTagManager().reset();}};var _4d=TiddlyWiki.prototype.removeTiddler;TiddlyWiki.prototype.removeTiddler=function(_4e){var _4f=this.fetchTiddler(_4e);var _50=_4f&&_4f.tags.length>0;_4d.apply(this,arguments);if(_50){abego.internal.getTagManager().reset();}};this.reset=function(){_3c=null;};this.getTiddlersWithTag=function(tag){_3d();var _52=_3c[tag];return _52?_52.tiddlers:null;};this.getAllTags=function(_53){_3d();var _54=[];for(var i in _3c){_54.push(i);}for(i=0;_53&&i<_53.length;i++){_54.pushUnique(_53[i],true);}abego.sortIgnoreCase(_54);return _54;};this.getTagInfos=function(){_3d();var _56=[];for(var _57 in _3c){_56.push([_57,_3c[_57]]);}return _56;};var _58=function(a,b){var a1=a[1];var b1=b[1];var d=b[1].count-a[1].count;return d!=0?d:abego.compareStrings(a[0].toLowerCase(),b[0].toLowerCase());};this.getSortedTagInfos=function(){_3d();var _5e=this.getTagInfos();_5e.sort(_58);return _5e;};this.getPartnerRankedTags=function(_5f){var _60={};for(var i=0;i<_5f.length;i++){var _62=this.getTiddlersWithTag(_5f[i]);for(var _63 in _62){var _64=store.getTiddler(_63);if(!(_64 instanceof Tiddler)){continue;}for(var j=0;j<_64.tags.length;j++){var tag=_64.tags[j];var c=_60[tag];_60[tag]=c?c+1:1;}}}var _68=abego.toSet(_5f);var _69=[];for(var n in _60){if(!_68[n]){_69.push(n);}}_69.sort(function(a,b){var d=_60[b]-_60[a];return d!=0?d:abego.compareStrings(a.toLowerCase(),b.toLowerCase());});return _69;};};abego.internal.getTagManager=function(){if(!abego.internal.gTagManager){abego.internal.gTagManager=new abego.internal.TagManager();}return abego.internal.gTagManager;};(function(){var _6e=2;var _6f=1;var _70=30;var _71;var _72;var _73;var _74;var _75;var _76;if(!abego.IntelliTagger){abego.IntelliTagger={};}var _77=function(){return _72;};var _78=function(tag){return _75[tag];};var _7a=function(s){var i=s.lastIndexOf(" ");return (i>=0)?s.substr(0,i):"";};var _7d=function(_7e){var s=_7e.value;var len=s.length;return (len>0&&s[len-1]!=" ");};var _81=function(_82){var s=_82.value;var len=s.length;if(len>0&&s[len-1]!=" "){_82.value+=" ";}};var _85=function(tag,_87,_88){if(_7d(_87)){_87.value=_7a(_87.value);}story.setTiddlerTag(_88.title,tag,0);_81(_87);abego.IntelliTagger.assistTagging(_87,_88);};var _89=function(n){if(_76&&_76.length>n){return _76[n];}return (_74&&_74.length>n)?_74[n]:null;};var _8b=function(n,_8d,_8e){var _8f=_89(n);if(_8f){_85(_8f,_8d,_8e);}};var _90=function(_91){var pos=_91.value.lastIndexOf(" ");var _93=(pos>=0)?_91.value.substr(++pos,_91.value.length):_91.value;return new RegExp(_93.escapeRegExp(),"i");};var _94=function(_95,_96){var _97=0;for(var i=0;i<_95.length;i++){if(_96[_95[i]]){_97++;}}return _97;};var _99=function(_9a,_9b,_9c){var _9d=1;var c=_9a[_9b];for(var i=_9b+1;i<_9a.length;i++){if(_9a[i][1].count==c){if(_9a[i][0].match(_9c)){_9d++;}}else{break;}}return _9d;};var _a0=function(_a1,_a2){var _a3=abego.internal.getTagManager().getSortedTagInfos();var _a4=[];var _a5=0;for(var i=0;i<_a3.length;i++){var c=_a3[i][1].count;if(c!=_a5){if(_a2&&(_a4.length+_99(_a3,i,_a1)>_a2)){break;}_a5=c;}if(c==1){break;}var s=_a3[i][0];if(s.match(_a1)){_a4.push(s);}}return _a4;};var _a9=function(_aa,_ab){return abego.filterStrings(abego.internal.getTagManager().getAllTags(_ab),_aa);};var _ac=function(){if(!_71){return;}var _ad=store.getTiddlerText("IntelliTaggerMainTemplate");if(!_ad){_ad="<b>Tiddler IntelliTaggerMainTemplate not found</b>";}_71.innerHTML=_ad;applyHtmlMacros(_71,null);refreshElements(_71,null);};var _ae=function(e){if(!e){var e=window.event;}var tag=this.getAttribute("tag");if(_73){_73.call(this,tag,e);}return false;};var _b2=function(_b3){createTiddlyElement(_b3,"span",null,"tagSeparator"," | ");};var _b4=function(_b5,_b6,_b7,_b8,_b9){if(!_b6){return;}var _ba=_b8?abego.toSet(_b8):{};var n=_b6.length;var c=0;for(var i=0;i<n;i++){var tag=_b6[i];if(_ba[tag]){continue;}if(c>0){_b2(_b5);}if(_b9&&c>=_b9){abego.createEllipsis(_b5);break;}c++;var _bf="";var _c0=_b5;if(_b7<10){_c0=createTiddlyElement(_b5,"span",null,"numberedSuggestion");_b7++;var key=_b7<10?""+(_b7):"0";createTiddlyElement(_c0,"span",null,"suggestionNumber",key+") ");var _c2=_b7==1?"Return or ":"";_bf=" (Shortcut: %1Alt-%0)".format([key,_c2]);}var _c3=config.views.wikified.tag.tooltip.format([tag]);var _c4=(_78(tag)?"Remove tag '%0'%1":"Add tag '%0'%1").format([tag,_bf]);var _c5="%0; Shift-Click: %1".format([_c4,_c3]);var btn=createTiddlyButton(_c0,tag,_c5,_ae,_78(tag)?"currentTag":null);btn.setAttribute("tag",tag);}};var _c7=function(){if(_71){window.scrollTo(0,ensureVisible(_71));}if(_77()){window.scrollTo(0,ensureVisible(_77()));}};var _c8=function(e){if(!e){var e=window.event;}if(!_71){return;}var _cb=resolveTarget(e);if(_cb==_77()){return;}if(abego.isDescendantOrSelf(_71,_cb)){return;}abego.IntelliTagger.close();};addEvent(document,"click",_c8);var _cc=Story.prototype.gatherSaveFields;Story.prototype.gatherSaveFields=function(e,_ce){_cc.apply(this,arguments);var _cf=_ce.tags;if(_cf){_ce.tags=_cf.trim();}};var _d0=function(_d1){story.focusTiddler(_d1,"tags");var _d2=abego.getTiddlerField(story,_d1,"tags");if(_d2){var len=_d2.value.length;abego.setRange(_d2,len,len);window.scrollTo(0,ensureVisible(_d2));}};var _d4=config.macros.edit.handler;config.macros.edit.handler=function(_d5,_d6,_d7,_d8,_d9,_da){_d4.apply(this,arguments);var _db=_d7[0];if((_da instanceof Tiddler)&&_db=="tags"){var _dc=_d5.lastChild;_dc.onfocus=function(e){abego.IntelliTagger.assistTagging(_dc,_da);setTimeout(function(){_d0(_da.title);},100);};_dc.onkeyup=function(e){if(!e){var e=window.event;}if(e.altKey&&!e.ctrlKey&&!e.metaKey&&(e.keyCode>=48&&e.keyCode<=57)){_8b(e.keyCode==48?9:e.keyCode-49,_dc,_da);}else{if(e.ctrlKey&&e.keyCode==32){_8b(0,_dc,_da);}}if(!e.ctrlKey&&(e.keyCode==13||e.keyCode==10)){_8b(0,_dc,_da);}setTimeout(function(){abego.IntelliTagger.assistTagging(_dc,_da);},100);return false;};_81(_dc);}};var _e0=function(e){if(!e){var e=window.event;}var _e3=resolveTarget(e);var _e4=_e3.getAttribute("tiddler");if(_e4){story.displayTiddler(_e3,_e4,"IntelliTaggerEditTagsTemplate",false);_d0(_e4);}return false;};var _e5=config.macros.tags.handler;config.macros.tags.handler=function(_e6,_e7,_e8,_e9,_ea,_eb){_e5.apply(this,arguments);abego.IntelliTagger.createEditTagsButton(_eb,createTiddlyElement(_e6.lastChild,"li"));};var _ec=function(){if(_71&&_72&&!abego.isDescendantOrSelf(document,_72)){abego.IntelliTagger.close();}};setInterval(_ec,100);abego.IntelliTagger.displayTagSuggestions=function(_ed,_ee,_ef,_f0,_f1){_74=_ed;_75=abego.toSet(_ee);_76=_ef;_72=_f0;_73=_f1;if(!_71){_71=createTiddlyElement(document.body,"div",null,"intelliTaggerSuggestions");_71.style.position="absolute";}_ac();abego.openAsPopup(_71);if(_77()){var w=_77().offsetWidth;if(_71.offsetWidth<w){_71.style.width=(w-2*(_6e+_6f))+"px";}abego.moveBelowAndClip(_71,_77());}else{abego.centerOnWindow(_71);}_c7();};abego.IntelliTagger.assistTagging=function(_f3,_f4){var _f5=_90(_f3);var s=_f3.value;if(_7d(_f3)){s=_7a(s);}var _f7=s.readBracketedList();var _f8=_f7.length>0?abego.filterStrings(abego.internal.getTagManager().getPartnerRankedTags(_f7),_f5,_70):_a0(_f5,_70);abego.IntelliTagger.displayTagSuggestions(_a9(_f5,_f7),_f7,_f8,_f3,function(tag,e){if(e.shiftKey){onClickTag.call(this,e);}else{_85(tag,_f3,_f4);}});};abego.IntelliTagger.close=function(){abego.closePopup(_71);_71=null;return false;};abego.IntelliTagger.createEditTagsButton=function(_fb,_fc,_fd,_fe,_ff,id,_101){if(!_fd){_fd="[edit]";}if(!_fe){_fe="Edit the tags";}if(!_ff){_ff="editTags";}var _102=createTiddlyButton(_fc,_fd,_fe,_e0,_ff,id,_101);_102.setAttribute("tiddler",(_fb instanceof Tiddler)?_fb.title:String(_fb));return _102;};abego.IntelliTagger.getSuggestionTagsMaxCount=function(){return 100;};config.macros.intelliTagger={label:"intelliTagger",handler:function(_103,_104,_105,_106,_107,_108){var _109=_107.parseParams("list",null,true);var _10a=_109[0]["action"];for(var i=0;_10a&&i<_10a.length;i++){var _10c=_10a[i];var _10d=config.macros.intelliTagger.subhandlers[_10c];if(!_10d){abego.alertAndThrow("Unsupported action '%0'".format([_10c]));}_10d(_103,_104,_105,_106,_107,_108);}},subhandlers:{showTags:function(_10e,_10f,_110,_111,_112,_113){_b4(_10e,_74,_76?_76.length:0,_76,abego.IntelliTagger.getSuggestionTagsMaxCount());},showFavorites:function(_114,_115,_116,_117,_118,_119){_b4(_114,_76,0);},closeButton:function(_11a,_11b,_11c,_11d,_11e,_11f){var _120=createTiddlyButton(_11a,"close","Close the suggestions",abego.IntelliTagger.close);},version:function(_121){var t="IntelliTagger %0.%1.%2".format([version.extensions.IntelliTaggerPlugin.major,version.extensions.IntelliTaggerPlugin.minor,version.extensions.IntelliTaggerPlugin.revision]);var e=createTiddlyElement(_121,"a");e.setAttribute("href","http://tiddlywiki.abego-software.de/#IntelliTaggerPlugin");e.innerHTML="<font color=\"black\" face=\"Arial, Helvetica, sans-serif\">"+t+"<font>";},copyright:function(_124){var e=createTiddlyElement(_124,"a");e.setAttribute("href","http://tiddlywiki.abego-software.de");e.innerHTML="<font color=\"black\" face=\"Arial, Helvetica, sans-serif\">© 2006-2007 <b><font color=\"red\">abego</font></b> Software<font>";}}};})();config.shadowTiddlers["IntelliTaggerStyleSheet"]="/***\n"+"!~IntelliTagger Stylesheet\n"+"***/\n"+"/*{{{*/\n"+".intelliTaggerSuggestions {\n"+"\tposition: absolute;\n"+"\twidth: 600px;\n"+"\n"+"\tpadding: 2px;\n"+"\tlist-style: none;\n"+"\tmargin: 0;\n"+"\n"+"\tbackground: #eeeeee;\n"+"\tborder: 1px solid DarkGray;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .currentTag {\n"+"\tfont-weight: bold;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .suggestionNumber {\n"+"\tcolor: #808080;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .numberedSuggestion{\n"+"\twhite-space: nowrap;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .intelliTaggerFooter {\n"+"\tmargin-top: 4px;\n"+"\tborder-top-width: thin;\n"+"\tborder-top-style: solid;\n"+"\tborder-top-color: #999999;\n"+"}\n"+".intelliTaggerSuggestions .favorites {\n"+"\tborder-bottom-width: thin;\n"+"\tborder-bottom-style: solid;\n"+"\tborder-bottom-color: #999999;\n"+"\tpadding-bottom: 2px;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .normalTags {\n"+"\tpadding-top: 2px;\n"+"}\n"+"\n"+".intelliTaggerSuggestions .intelliTaggerFooter .button {\n"+"\tfont-size: 10px;\n"+"\n"+"\tpadding-left: 0.3em;\n"+"\tpadding-right: 0.3em;\n"+"}\n"+"\n"+"/*}}}*/\n";config.shadowTiddlers["IntelliTaggerMainTemplate"]="<!--\n"+"{{{\n"+"-->\n"+"<div class=\"favorites\" macro=\"intelliTagger action: showFavorites\"></div>\n"+"<div class=\"normalTags\" macro=\"intelliTagger action: showTags\"></div>\n"+"<!-- The Footer (with the Navigation) ============================================ -->\n"+"<table class=\"intelliTaggerFooter\" border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tbody>\n"+" <tr>\n"+"\t<td align=\"left\">\n"+"\t\t<span macro=\"intelliTagger action: closeButton\"></span>\n"+"\t</td>\n"+"\t<td align=\"right\">\n"+"\t\t<span macro=\"intelliTagger action: version\"></span>, <span macro=\"intelliTagger action: copyright \"></span>\n"+"\t</td>\n"+" </tr>\n"+"</tbody></table>\n"+"<!--\n"+"}}}\n"+"-->\n";config.shadowTiddlers["IntelliTaggerEditTagsTemplate"]="<!--\n"+"{{{\n"+"-->\n"+"<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler'></div>\n"+"<div class='title' macro='view title'></div>\n"+"<div class='tagged' macro='tags'></div>\n"+"<div class='viewer' macro='view text wikified'></div>\n"+"<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler'></div>\n"+"<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>\n"+"<!--\n"+"}}}\n"+"-->\n";config.shadowTiddlers["BSD open source license (abego Software)"]="See [[Licence|http://tiddlywiki.abego-software.de/#%5B%5BBSD%20open%20source%20license%5D%5D]].";config.shadowTiddlers["IntelliTaggerPlugin Documentation"]="[[Documentation on abego Software website|http://tiddlywiki.abego-software.de/doc/IntelliTagger.pdf]].";config.shadowTiddlers["IntelliTaggerPlugin SourceCode"]="[[Plugin source code on abego Software website|http://tiddlywiki.abego-software.de/archive/IntelliTaggerPlugin/Plugin-IntelliTagger-src.1.0.2.js]]\n";(function(){var _126=restart;restart=function(){setStylesheet(store.getTiddlerText("IntelliTaggerStyleSheet"),"IntelliTaggerStyleSheet");_126.apply(this,arguments);};})();}
// %/
|''URL:''|http://jackparke.googlepages.com/jtw.html|
|''Description:''|Plugins, Macros and Hacks|
|''Author:''|JackParker|
|''URL:''|http://tw.lewcid.org/|
|''Description:''|a repository of my extensions for TW|
|''Author:''|SaqImtiaz|
{{floatleft{
<<toggleSideBar . "" show>>
/% open tiddler:
[[t●|TspotControls]]
or use popup: %/
<<tiddler ShowPopup with: TspotControls "t●" "Tspot Controls" bold auto sticky>>
<<tiddler ShowPopup with: Bookmarklets "≡" "TiddlyWiki InstantBookmarklets" "" auto "">>
[[todo]][[scratchpad]]
<<tag memorize>>
<<tag keyboard>>
[[Google|http://www.google.com]]
}}}
/%@@margin:0 48em;@@%/
{{floatright{
new: {{tiny{<<newTiddler label:"*tiddler">><<newJournal label:"*journal">>}}}
}}}
{{clear block{}}}
<!--{{{-->
<script> // See StorySaverPlugin for more info
if (window.coreTweaks_getParameters==undefined) {
window.coreTweaks_getParameters=window.getParameters;
window.getParameters=function() {
var p=window.coreTweaks_getParameters.apply(this,arguments);
if (!p) {
var cookies = document.cookie.split("; ");
for (var c=0; c<cookies.length; c++) {
var name=cookies[c].split("=")[0]; var value=cookies[c].split("=")[1];
if (name=="txtSavedStory" && value.length) p=unescape(value);
}
}
return p;
}
}
</script>
<!--}}}-->
|''URL:''|http://www.martinswiki.com/ |
|''Description:''|Martin Buddens's Plugins |
|''Author:''|MartinBudden |
/***
|Name|MatchTagsPlugin|
|Source|http://www.TiddlyTools.com/#MatchTagsPlugin|
|Documentation|http://www.TiddlyTools.com/#MatchTagsPluginInfo|
|Version|2.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|'tag matching' with full boolean expressions (AND, OR, NOT, and nested parentheses)|
!!!!!Documentation
> see [[MatchTagsPluginInfo]]
!!!!!Revisions
<<<
2008.09.04 [2.0.0] added "report" and "panel" options to generate formatted results and store in a tiddler. Also, added config.macros.matchTags.formatList(place,fmt,sep) API to return formatted output for use with other plugins/scripts
| please see [[MatchTagsPluginInfo]] for additional revision details |
2008.02.28 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.matchTags= {major: 2, minor: 0, revision: 0, date: new Date(2008,9,4)};
// store.getMatchingTiddlers() processes boolean expressions for tag matching
// sortfield (optional) sets sort order for tiddlers - default=title
// tiddlers (optional) use alternative set of tiddlers (instead of current store)
TiddlyWiki.prototype.getMatchingTiddlers = function(tagexpr,sortfield,tiddlers) {
var debug=config.options.chkDebug; // abbreviation
var cmm=config.macros.matchTags; // abbreviation
var r=[]; // results are an array of tiddlers
var tids=tiddlers||store.getTiddlers(sortfield||"title");
if (tiddlers && sortfield) store.sortTiddlers(tids,sortfield);
if (debug) displayMessage(cmm.msg1.format([tids.length]));
// try simple lookup to quickly find single tags or tags that
// contain boolean operators as literals, e.g. "foo and bar"
for (var t=0; t<tids.length; t++)
if (tids[t].isTagged(tagexpr)) r.pushUnique(tids[t]);
if (r.length) {
if (debug) displayMessage(cmm.msg4.format([r.length,tagexpr]));
return r;
}
// convert expression into javascript code with regexp tests,
// so that "tag1 AND ( tag2 OR NOT tag3 )" becomes
// "/\~tag1\~/.test(...) && ( /\~tag2\~/.test(...) || ! /\~tag3\~/.test(...) )"
// normalize whitespace, tokenize operators, delimit with "~"
var c=tagexpr.trim(); // remove leading/trailing spaces
c = c.replace(/\s+/ig," "); // reduce multiple spaces to single spaces
c = c.replace(/\(\s?/ig,"~(~"); // open parens
c = c.replace(/\s?\)/ig,"~)~"); // close parens
c = c.replace(/(\s|~)?&&(\s|~)?/ig,"~&&~"); // &&
c = c.replace(/(\s|~)AND(\s|~)/ig,"~&&~"); // AND
c = c.replace(/(\s|~)?\|\|(\s|~)?/ig,"~||~"); // ||
c = c.replace(/(\s|~)OR(\s|~)/ig,"~||~"); // OR
c = c.replace(/(\s|~)?!(\s|~)?/ig,"~!~"); // !
c = c.replace(/(^|~|\s)NOT(\s|~)/ig,"~!~"); // NOT
c = c.replace(/(^|~|\s)NOT~\(/ig,"~!~("); // NOT(
// change tag terms to regexp tests
var terms=c.split("~"); for (var i=0; i<terms.length; i++) { var t=terms[i];
if (/(&&)|(\|\|)|[!\(\)]/.test(t) || t=="") continue; // skip operators/parens/spaces
if (t==config.macros.matchTags.untaggedKeyword)
terms[i]="tiddlertags=='~~'"; // 'untagged' tiddlers
else
terms[i]="/\\~"+t+"\\~/.test(tiddlertags)";
}
c=terms.join(" ");
if (debug) { displayMessage(cmm.msg2.format([tagexpr])); displayMessage(cmm.msg3.format([c])); }
// scan tiddlers for matches
for (var t=0; t<tids.length; t++) {
// assemble tags from tiddler into string "~tag1~tag2~tag3~"
var tiddlertags = "~"+tids[t].tags.join("~")+"~";
try { if(eval(c)) r.push(tids[t]); } // test tags
catch(e) { // error in test
displayMessage(cmm.msg2.format([tagexpr]));
displayMessage(cmm.msg3.format([c]));
displayMessage(e.toString());
break; // skip remaining tiddlers
}
}
if (debug) displayMessage(cmm.msg4.format([r.length,tagexpr]));
return r;
}
//}}}
//{{{
config.macros.matchTags = {
msg1: "scanning %0 input tiddlers",
msg2: "looking for '%0'",
msg3: "using expression: '%0'",
msg4: "found %0 tiddlers matching '%1'",
noMatch: "no matching tiddlers",
untaggedKeyword: "-",
untaggedLabel: "no tags",
untaggedPrompt: "show tiddlers with no tags",
defTiddler: "MatchingTiddlers",
defFormat: "%0",
defSeparator: "\n",
reportHeading: "Found %0 tiddlers tagged with: '{{{%1}}}'\n----\n",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var mode=params[0]?params[0].toLowerCase():'';
if (mode=="inline")
params.shift();
if (mode=="report" || mode=="panel") {
params.shift();
var target=params.shift()||this.defTiddler;
}
if (mode=="popup") {
params.shift();
if (params[0]&¶ms[0].substr(0,6)=="label:") var label=params.shift().substr(6);
if (params[0]&¶ms[0].substr(0,7)=="prompt:") var prompt=params.shift().substr(7);
} else {
var fmt=(params.shift()||this.defFormat).unescapeLineBreaks();
var sep=(params.shift()||this.defSeparator).unescapeLineBreaks();
}
var sortBy="+title";
if (params[0]&¶ms[0].substr(0,5)=="sort:") sortBy=params.shift().substr(5);
var expr = params.join(" ");
if (mode!="panel" && (!expr||!expr.trim().length)) return;
if (expr==this.untaggedKeyword)
{ var label=this.untaggedLabel; var prompt=this.untaggedPrompt };
switch (mode) {
case "popup": this.createPopup(place,label,expr,prompt,sortBy); break;
case "panel": this.createPanel(place,expr,fmt,sep,sortBy,target); break;
case "report": this.createReport(target,expr,fmt,sep,sortBy); break;
case "inline": default: this.createInline(place,expr,fmt,sep,sortBy); break;
}
},
formatList: function(tids,fmt,sep) {
var out=[];
for (var t=0; t<tids.length; t++) {
var title="[["+tids[t].title+"]]";
var who=tids[t].modifier;
var when=tids[t].modified.toLocaleString();
var text=tids[t].text;
var first=tids[t].text.split("\n")[0];
var desc=store.getTiddlerSlice(tids[t].title,"description");
desc=desc||store.getTiddlerSlice(tids[t].title,"Description");
desc=desc||store.getTiddlerText(tids[t].title+"##description");
desc=desc||store.getTiddlerText(tids[t].title+"##Description");
out.push(fmt.format([title,who,when,text,first,desc]));
}
return out.join(sep);
},
createInline: function(place,expr,fmt,sep,sortBy) {
wikify(this.formatList(store.sortTiddlers(store.getMatchingTiddlers(expr),sortBy),fmt,sep),place);
},
createPopup: function(place,label,expr,prompt,sortBy) {
var btn=createTiddlyButton(place,
(label||expr).format([expr]),
(prompt||config.views.wikified.tag.tooltip).format([expr]),
function(ev){ return config.macros.matchTags.showPopup(this,ev||window.event); });
btn.setAttribute("sortBy",sortBy);
btn.setAttribute("expr",expr);
},
showPopup: function(here,ev) {
var p=Popup.create(here); if (!p) return false;
var tids=store.getMatchingTiddlers(here.getAttribute("expr"));
store.sortTiddlers(tids,here.getAttribute("sortBy"));
var list=[]; for (var t=0; t<tids.length; t++) list.push(tids[t].title);
if (!list.length) createTiddlyText(p,this.noMatch);
else {
var b=createTiddlyButton(createTiddlyElement(p,"li"),
config.views.wikified.tag.openAllText,
config.views.wikified.tag.openAllTooltip,
function() {
var list=this.getAttribute("list").readBracketedList();
story.displayTiddlers(null,tids);
});
b.setAttribute("list","[["+list.join("]] [[")+"]]");
createTiddlyElement(p,"hr");
}
var out=this.formatList(tids," %0 ","\n"); wikify(out,p);
Popup.show(p,false);
ev.cancelBubble=true;
if(ev.stopPropagation) ev.stopPropagation();
return false;
},
createReport: function(target,expr,fmt,sep,sortBy) {
var tids=store.sortTiddlers(store.getMatchingTiddlers(expr),sortBy);
if (!tids.length) { displayMessage('no matches for: '+expr); return false; }
var msg=config.messages.overwriteWarning.format([target]);
if (store.tiddlerExists(target) && !confirm(msg)) return false;
var out=this.reportHeading.format([tids.length,expr])
out+=this.formatList(tids,fmt,sep);
store.saveTiddler(target,target,out,config.options.txtUserName,new Date(),[],{});
story.closeTiddler(target); story.displayTiddler(null,target);
},
createPanel: function(place,expr,fmt,sep,sortBy,tid) {
var html="<form style='display:inline'><!-- \
--><input type='text' name='expr' style='width:55%' title='tag expression'><!-- \
--><input type='text' name='fmt' style='width:10%' title='list item format'><!-- \
--><input type='text' name='sep' style='width:5%' title='list item separator'><!-- \
--><input type='text' name='tid' style='width:20%' title='target tiddler title'><!-- \
--><input type='button' name='go' style='width:8%' value='go' onclick=\" \
var expr=this.form.expr.value; \
if (!expr.length) { alert('Enter a boolean tag expression'); return false; } \
var fmt=this.form.fmt.value; \
if (!fmt.length) { alert('Enter the list item output format'); return false; } \
var sep=this.form.sep.value.unescapeLineBreaks(); \
var tid=this.form.tid.value; \
if (!tid.length) { alert('Enter a target tiddler title'); return false; } \
config.macros.matchTags.createReport(tid,expr,fmt,sep,'title'); \
return false;\"> \
</form>";
var s=createTiddlyElement(place,"span"); s.innerHTML=html;
var f=s.getElementsByTagName("form")[0];
f.expr.value=expr; f.fmt.value=fmt; f.sep.value=sep.escapeLineBreaks(); f.tid.value=tid;
}
};
//}}}
//{{{
// SHADOW TIDDLER for displaying default panel input form
config.shadowTiddlers.MatchTags="{{smallform{<<matchTags panel>>}}}";
//}}}
//{{{
// TWEAK core filterTiddlers() for enhanced boolean matching in [tag[...]] syntax:
// use getMatchingTiddlers instead getTaggedTiddlers
var fn=TiddlyWiki.prototype.filterTiddlers;
fn=fn.toString().replace(/getTaggedTiddlers/g,"getMatchingTiddlers");
eval("TiddlyWiki.prototype.filterTiddlers="+fn);
//}}}
//{{{
// REDEFINE core handler for enhanced boolean matching in tag:"..." paramifier
// use filterTiddlers() instead of getTaggedTiddlers() to get list of tiddlers.
config.paramifiers.tag = {
onstart: function(v) {
var tagged = store.filterTiddlers("[tag["+v+"]]");
story.displayTiddlers(null,tagged,null,false,null);
}
};
//}}}
//
// Note: This is a modified version of the X11 (aka MIT) open source
// license. It lets you use, modify, distribute and sell, etc.,
// requiring only that you leave the "Help" and "About Memorizable
// Tables" links (under "Options") in tact. If you desire to use the
// software without these links please contact the author.
//
// COPYRIGHT AND PERMISSION NOTICE for Memorizable Tables
//
// Copyright (c) 2007, Craig D. Muth, memorizable.com
// Author's Website URL: http://memorizable.com
//
// All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished
// to do so, subject to the following conditions:
//
// The above copyright notice, Author's Website URL, and this
// permission notice shall be included in all copies or substantial
// portions of the Software, and any hyperlinks in the user interface
// in the Software which refer to any page on the Author's Website may
// not be removed, disabled, altered, obscured, or repositioned.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// Except as contained in this notice, the name of a copyright holder
// shall not be used in advertising or otherwise to promote the sale,
// use or other dealings in this Software without prior written
// authorization of the copyright holder.
//
Mem = new Object();
Mem.blankRowCount = 9;
Mem.mGray = "#d8d4c0";
Mem.mGreen = "#fff";
Mem.mClicked = "#b8b4a0";
Mem.myCellIndex = function(th) {
var cells = th.parentNode.cells;
var inn = 0;
for(var x=0; x<cells.length; x++) {
if(cells.item(x) == th)
inn = x;
}
return inn;
}
Mem.start = function( item ) {
var columnClicked;
item.parentNode.parentNode.parentNode.parentNode.isMem = true;
var t = this.setT( item );
columnClicked = Mem.myCellIndex(item.parentNode);
// If already in progress
if( t.s && t.s.tbodyBackup ) {
// Kill blinking processes
this.tChile('directionsDiv').cycles = 1;
Mem.restore();
}
// Create new if necessary
if( typeof( t.s ) != 'object')
t.s = new Array();
t.s.column = columnClicked;
// Create backup
var bak = t.tBodies[0].cloneNode( true );
t.s.tbodyBackup = bak;
// Init correct count
t.s.correctCount = 0;
t.s.pending = new Array();
var initialLength = t.tBodies[0].rows.length;
for(var x=1; x<initialLength; x++) {
// Build up list of indexes
t.s.pending[t.s.pending.length] = t.tBodies[0].rows[1];
// Remove from table
t.tBodies[0].removeChild( t.tBodies[0].rows[1] );
}
t.s.totalQuestions = t.s.pending.length;
var tds = t.s.pending[0].getElementsByTagName("TD");
var numberOfColumns=tds.length;
// Add blank rows to end
for(var x=1; x<t.s.pending.length; x++) {
if( x <= this.blankRowCount ) {
var tr = document.createElement("TR");
// For each column
for(var y=0; y<numberOfColumns; y++) {
var td = document.createElement("TD"); td.innerHTML = " ";
tr.appendChild( td );
}
t.tBodies[0].appendChild( tr );
}
}
// If hidden blank rows
if( t.s.pending.length > this.blankRowCount + 1 ) {
// Add ... row
var tr = document.createElement("TR");
var td = document.createElement("TD");
// td.innerHTML = ". . .";
td.innerHTML = "<div style='text-align: center; font-weight: bold; font-size: 6px; font-family: arial black; margin-top: 2px;'>. . .</div>";
var colspan = document.createAttribute("COLSPAN");
colspan.nodeValue=numberOfColumns;
td.setAttributeNode(colspan);
tr.appendChild( td );
//numberOfColumns
t.tBodies[0].appendChild( tr );
}
this.shuffle( t.s.pending ); t.s.pending.reverse(); this.shuffle( t.s.pending );
// Add buttons, etc. to end of table.
var tr = document.createElement("TR");
var statusTd = document.createElement("TD");
statusTd.id = 'statusTd';
tr.appendChild( statusTd );
var colspan = document.createAttribute("COLSPAN");
colspan.nodeValue=numberOfColumns;
statusTd.setAttributeNode(colspan);
t.tBodies[0].appendChild( tr );
// Create placeholders for buttons, etc.
statusTd.innerHTML = "\
<div id=mode style='text-align:right; height:19px; font-size:10px; color:#666;'>" + Mem.getModeDiv(0) + "</div>\
<div id=directionsDiv style='margin-bottom:4px; text-align: left; font-size:10px; font-family:verdana,arial,sans-serif; color:#666;'></div>\
<div id=buttons style='float:left; height:21px;'></div>\
<div id=options style='padding: 5px 0px 0px 8px; width:55px; margin-top:0px; float:right;'><a href='#' onclick='return Mem.showOptions(this);' id=optionsLink>Options</a></div>\
<div id=progress style='margin-top:6px; float:right; font-size:8px; font-family:impact; color:#aaa; text-align:right; vertical-align:middle; '></div>\
" + this.getOptions();
// Enable options if enabled before
if( t.s.optionsOn )
this.showOptions( statusTd );
this.presentQuestion();
this.glow(100);
t.s.mode = "flashcard";
return false;
}
Mem.addEvent = function( obj, type, fn ) {
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function() {obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, false );
}
Mem.getQuestionCell = function() {
return Mem.t.s.pending[0].cells[ Mem.t.s.column ];
}
Mem.createProgressBar = function() {
var progress = "";
var progressDups = "";
var foundAlready = new Array();
for(var x=0; x<Mem.t.s.pending.length ;x++) {
// If found already
if( foundAlready[ Mem.t.s.pending[x].innerHTML ] )
progressDups += "|";
else
progress += "|";
// Remember we found this one
foundAlready[ Mem.t.s.pending[x].innerHTML ] = true;
}
return progress + "<span style='color:#f00;'>" + progressDups + "</span>";
}
Mem.presentQuestion = function() {
this.tChile('directionsDiv').innerHTML =
"<div style='text-align:center;'>Guess the answer <b style='color:#4d0'>in your head</b>.<span style='font-size:7px;'></span> Then click <b>show answer</b>, or type <b>1</b>.</div>";
this.tChile('buttons').innerHTML = "<button id=showAnswer style='margin-right:111px; width:11em; margin-bottom:1px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.showAnswer( this )' >show answer <span style='color:#aaa;text-decoration:underline;'>1</span></button>";
var iveGuessed = this.tChile('showAnswer');
Mem.addEvent( iveGuessed, 'mouseover', function(){ if(typeof( iveGuessedOnMouseOver ) =='function') iveGuessedOnMouseOver() } );
Mem.addEvent( iveGuessed, 'mouseout', function(){ if(typeof( iveGuessedOnMouseOver ) =='function') iveGuessedOnMouseOut() } );
// Add pending row
Mem.t.tBodies[0].insertBefore( Mem.t.s.pending[0], Mem.t.tBodies[0].rows[ Mem.t.s.correctCount + 1 ] );
// Insert "guess the answer", remembering old value
var questionCell = this.getQuestionCell();
Mem.t.s.questionCellOld = questionCell.innerHTML;
questionCell.innerHTML = "<span style='text-decoration:none; color:#4d0; font-weight:bold; cursor:pointer;' title=\"Guess the answer in your head. Then, click the 'show answer' button.\">what goes here?</span>";
// Help alert
Mem.addEvent( questionCell.getElementsByTagName("SPAN")[0], 'mousedown', function(){ alert('Guess the answer in your head. Then, click the \'show answer\' button at the bottom of the table.') } );
this.tChile('progress').innerHTML = this.createProgressBar();
}
Mem.showAnswer = function( button, noScroll ) {
var t = this.setT( button );
// Exit if other mode
if( t.s.mode != "flashcard" )
return;
// Exit if no answer to show
if( t.s.questionCellOld == null )
return;
var questionCell = this.getQuestionCell();
questionCell.innerHTML = t.s.questionCellOld;
t.s.questionCellOld = null;
// Default
var iWasRightText = "I was right";
// Count how many of this remaining
var timesFound = 0;
for(var x=0; x<t.s.pending.length ;x++)
if( t.s.pending[x].innerHTML == t.s.pending[0].innerHTML )
timesFound++;
// If not the last time
if( timesFound > 1 )
iWasRightText = "show later";
this.tChile('directionsDiv').innerHTML =
"<div style='text-align:center;'>Press the appropriate button based on your guess, or type <b>1</b> or <b>2</b>.</div>";
this.tChile('buttons').innerHTML = "\
<button id=iWasWrong style='width:11em; padding:0px; margin: 0px 12px 1px 0px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.answer( false, this )'>I was wrong <span style='color:#aaa;text-decoration:underline;'>1</span></button>\
<button id=iWasRight class='iWasRightButton' style='width:10em; margin-bottom:1px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.answer( true, this )' >" + iWasRightText + " <span style='color:#aaa;text-decoration:underline;'>2</span></button>\
";
this.tChile('progress').innerHTML = this.createProgressBar();
var iWasRight = this.tChile('iWasRight');
var iWasWrong = this.tChile('iWasWrong');
Mem.addEvent( iWasRight, 'mouseover', function(){ if(typeof( iWasRightOnMouseOver ) =='function') iWasRightOnMouseOver() } );
Mem.addEvent( iWasRight, 'mouseout', function(){ if(typeof( iWasRightOnMouseOut ) =='function') iWasRightOnMouseOut() } );
Mem.addEvent( iWasWrong, 'mouseover', function(){ if(typeof( iWasWrongOnMouseOver ) =='function') iWasWrongOnMouseOver() } );
Mem.addEvent( iWasWrong, 'mouseout', function(){ if(typeof( iWasWrongOnMouseOut ) =='function') iWasWrongOnMouseOut() } );
if(! noScroll)
this.scrollDownIfNecessary( this.tChile('statusTd') );
}
Mem.answer = function( correct, button, noScroll ) {
var t = this.setT( button );
// If answer not shown
if( t.s.questionCellOld != null )
return;
// If other mode
if( t.s.mode != "flashcard" )
return;
var dup = this.currentIsDuplicate();
var last = t.s.pending[0];
// Remove from front of pending
t.s.pending.splice( 0, 1 );
var allRows = t.tBodies[0].rows;
if( correct ) {
// If elsewhere in pending, remove from table
if( dup )
t.tBodies[0].removeChild( last );
// If pending is empty, they're finished
if( t.s.pending.length == 0 ) {
this.finished();
return;
}
// If not dup, increase count of correct
if( ! dup ) {
t.s.correctCount++;
// If enough rows in table, remove last one (blank or ...)
if( t.s.correctCount + this.blankRowCount >= t.s.totalQuestions - 1 )
t.tBodies[0].removeChild( allRows[allRows.length - 2] );
}
}
// If they missed it
else {
// Remove from table
t.tBodies[0].removeChild( last );
t.s.pending.push( last );
t.s.pending.splice( 2, 0, last );
}
this.presentQuestion();
if(this.tChile('directionsDiv').cycles >= 3)
this.tChile('directionsDiv').cycles = 2;
if(! noScroll)
this.scrollDownIfNecessary( this.tChile('statusTd') );
}
Mem.currentIsDuplicate = function() {
for(var x=1; x<Mem.t.s.pending.length ;x++) {
if( Mem.t.s.pending[x] == Mem.t.s.pending[0] )
return true;
}
return false;
}
Mem.message = function( s ) {
var d = document.createElement('div');
var t = document.createTextNode( s );
d.appendChild(t);
document.body.appendChild(d);
}
Mem.shuffle = function( list ) {
var holder, swaps, i, j;
for (swaps=0; swaps<(list.length*2); swaps++) {
i = Math.floor(Math.random()*list.length);
j = Math.floor(Math.random()*list.length);
holder = list[i];
list[i] = list[j];
list[j]=holder;
}
return list;
}
Mem.dump = function( o ) {
var s = "";
for(m in o)
s += m + ", ";
return s;
}
Mem.keyWasPressed = function( keyp ) {
var pressed;
if( navigator.appName == "Netscape" ) pressed = keyp.which;
if( navigator.appVersion.indexOf("MSIE") != -1 ) pressed = event.keyCode;
// In case no table in progress
try {
// Show answer
if ( ( pressed == "1".charCodeAt(0) ) || ( pressed == 97 ) ) {
// If answer not shown yet
if( Mem.t.s.questionCellOld != null )
Mem.showAnswer();
else
Mem.answer( false );
}
// TODO make sure there are no modifiers held down (because of ctrl-r)
// I was right
if ( ( pressed == "2".charCodeAt(0) ) || ( pressed == 98 ) )
Mem.answer( true );
} catch(e) {}
}
Mem.memorizeAllTables = function( item, onlyDoTheseTables ) {
// If we are a "hide" link
if( item.innerHTML == "close" ) {
item.innerHTML = item.innerHTML_old;
var removeThis = item.parentNode.getElementsByTagName("DIV")[0];
// Close and exit
item.parentNode.removeChild( removeThis );
return false;
}
// Change link to 'close'
item.innerHTML_old = item.innerHTML;
item.innerHTML = "close";
// Create table in new div
var d = document.createElement("div");
d.innerHTML = "\
<table class=\"memorizableAll\"><tr> \
<th>Left Side <a style=\"font-size: 9px;\" href=\"#\" onclick=\"return Mem.start(this)\">(memorize)</a></th> \
<th>Right Side <a style=\"font-size: 9px;\" href=\"#\" onclick=\"return Mem.start(this)\">(memorize)</a></th>\
</tr></table>";
// Get ref to it
var tb = d.getElementsByTagName("TBODY")[0];
var memTableCount = 0;
// Convert list to map
var onlyMap = [];
if( onlyDoTheseTables )
for(var x=0; x<onlyDoTheseTables.length; x++)
onlyMap[ onlyDoTheseTables[x].toString() ] = true;
// For each table
var ts = document.getElementsByTagName("table");
for(var x=0; x<ts.length; x++) {
// In case null pointer when seeking anchor
try {
// If mem table
if( ts[x].id == "memTable" ) {
memTableCount++;
if( onlyDoTheseTables && ! onlyMap[memTableCount.toString()] )
continue;
var rs = ts[x].rows;
// If in progress, use backup
if( ts[x].s && ts[x].s.tbodyBackup )
rs = ts[x].s.tbodyBackup.rows;
// Add each row to the table
for(var z=1; z<rs.length; z++)
tb.appendChild( rs[z].cloneNode( true ) );
}
} catch(e) {}
}
// Append div
item.parentNode.appendChild( d )
// Start a session, using the 2nd "(memorize)" link
Mem.start( d.getElementsByTagName("A")[1] );
return false;
}
// Returns Y coord of top of element.
Mem.findY = function( o ) {
var curtop = 0;
if (o.offsetParent) {
curtop = o.offsetTop
while (o = o.offsetParent)
curtop += o.offsetTop
}
return curtop;
}
// Get distance from page top to window bottom
Mem.getWindowBottomY = function() {
// Get scrollY
var scrollY = document.body.scrollTop;
if( window.pageYOffset )
scrollY = window.pageYOffset
var winY = document.body.clientHeight;
if( window.innerHeight )
winY = window.innerHeight;
return scrollY + winY;
}
Mem.scrollDownIfNecessary = function( obj ) {
// If last row close to getting off-screen
if( this.findY( obj ) + 55 > this.getWindowBottomY() ) {
// Scroll down smoothly
var myInterval = window.setInterval(function () { window.scrollBy( 0, 2 ); }, 10);
window.setTimeout(function () { clearInterval(myInterval); },650);
}
}
Mem.startFirst = function(level) {
var as = byid('memTable').getElementsByTagName('a');
var a = as.length == 1 ? as[0] : as[1];
Mem.start( a );
// If 2, start another record
if(level == 2) {
Mem.showAnswer(this.tChile('showAnswer'), true);
Mem.answer(true, this.tChile('iWasRightButton'), true);
this.tChile('directionsDiv').cycles = 100;
}
}
Mem.parents = function(node, levels) {
for(x=1;x<=levels;x++) node = node.parentNode;
return node;
}
Mem.showOptions = function(node) {
this.setT(node);
this.tChile('optionsLink').style.display="none";
this.tChile('optionsBox').style.display="block";
Mem.t.s.optionsOn = true;
// Don't let clicking on options change default table
this.restoreTBody();
return false;
}
Mem.hideOptions = function(node) {
this.setT(node);
this.tChile('optionsLink').style.display="block";
this.tChile('optionsBox').style.display="none";
Mem.t.s.optionsOn = false;
// Don't let clicking on options change default table
this.restoreTBody();
return false;
}
Mem.close = function( node ) {
var t = this.setT( node );
// Don't re-open options
Mem.t.s.optionsOn = false;
Mem.restore();
// Invoke hook if reset
if(node != null) {
// In case method not there
try {
mem_close( t );
} catch(e) {}
}
return false;
}
Mem.finished = function() {
var directions = this.tChile('directionsDiv');
var buttons = this.tChile('buttons');
// Default values
directions.innerHTML = "<div style='text-align:center;'>Congratulations, you've finished.</div>";
buttons.innerHTML = "";
// Restore rows
this.addRowsFromBackup();
// Call hook
try {
mem_finished( [directions, buttons] );
} catch(e) {}
Mem.glow(2, "finished");
return false;
}
Mem.startOver = function( node ) {
var t = this.setT( node );
if( t.s.mode == "flashcard" )
Mem.start( t.getElementsByTagName('a')[t.s.column] );
else if( t.s.mode == "matching" )
Mem.startMatching( t );
return false;
}
Mem.startMatching = function( node ) {
var t = this.setT( node );
t.s.match0 = t.s.match1 = null;
// Change help text
this.tChile('mode').innerHTML = Mem.getModeDiv(1);
this.tChile('directionsDiv').innerHTML =
"<div style='text-align:center;'><b>Note:</b> this table has been <i style='font-weight:bold; color:#f90; cursor: pointer;'><span onclick='Mem.startOver(this);'>shuffled</span></i>. Click items to identify matches.</div>";
this.tChile('buttons').innerHTML = "";
this.tChile('progress').innerHTML = "";
var rows = t.rows;
// Add rows from backup
this.addRowsFromBackup();
// Format them
rows = t.rows;
for(var x=1; x<(rows.length-1); x++) {
var tds = rows[x].cells;
// Add click events
Mem.addEvent( tds[0], 'click', function(){ Mem.matchingClicked( this, 0 ) } );
Mem.addEvent( tds[1], 'click', function(){ Mem.matchingClicked( this, 1 ) } );
tds[0].style.cursor = tds[1].style.cursor = "pointer";
tds[0].style.background = tds[1].style.background = tds[0].style.endColor = tds[1].style.endColor = Mem.mGray;
// Add indexes
tds[0].mIndex = tds[1].mIndex = x;
}
// Shuffle columns
for (swaps=0; swaps<(rows.length*4); swaps++) {
Mem.swapOnce(rows,0);
Mem.swapOnce(rows,1);
}
this.glow(100);
t.s.mode = "matching";
return false;
}
Mem.matchingClicked = function(cell, side) {
// Exit if already correct
if(cell.mState == "correct")
return;
var t = this.setT( cell );
var rows = t.rows;
// Update colors of others, and count remaining
var remaining = 0;
for(var x=1; x<(rows.length-1); x++) {
var td = rows[x].cells[side];
// If gray, clear it
if((cell != td) && (td.mState == "guess")) {
td.mState = null;
td.style.background = td.endColor= Mem.mGray;
}
if(td.mState != "correct") remaining++;
}
// Remember this was clicked
if(side == 0) t.s.match0 = cell;
else t.s.match1 = cell;
// If already guessed
if(cell.mState == "guess") {
cell.mState = null;
cell.style.background = cell.endColor = Mem.mGray;
// Clear it
if(side == 0) t.s.match0 = null;
else t.s.match1 = null;
} else {
// Make it selected
cell.mState = "guess";
cell.style.background = cell.endColor = Mem.mClicked;
}
// Exit if neither are selected
if(! (t.s.match0 && t.s.match1))
return;
// Go through backup table and look for matches
var found = false;
var backupRows = t.s.tbodyBackup.getElementsByTagName('tr');
for(var x=1; x<backupRows.length; x++) {
var tds = backupRows[x].getElementsByTagName('td');
if((trim(t.s.match0.innerHTML) == trim(tds[0].innerHTML))
&& (trim(t.s.match1.innerHTML) == trim(tds[1].innerHTML)))
found = true;
}
// If match
if(found) {
var directions = this.tChile('directionsDiv');
if(directions.cycles > 2)
directions.cycles = 2;
// Make me dark green
t.s.match0.mState = t.s.match1.mState = "correct";
t.s.match0.endColor = t.s.match1.endColor = Mem.mGreen;
t.s.match0.style.cursor = t.s.match1.style.cursor = "";
// If finished - congrats message, restore rows
if(remaining == 1) {
directions.innerHTML = "<div style='text-align:center;'>Congratulations, you've finished. \
Try <a href='#' onclick='return Mem.flashcardMode(this)'>flashcard mode</a>.</div>";
Mem.glow(2, "finished");
this.addRowsFromBackup();
} else {
cell.style.background = Mem.mGray;
Mem.glow(1, "green", t.s.match0, Mem.mGreen);
Mem.glow(1, "green", t.s.match1, Mem.mGreen);
}
t.s.match0 = t.s.match1 = null;
return;
}
// Must not have been found
cell.style.background = Mem.mGray;
Mem.glow(1, "red", cell, Mem.mClicked);
}
Mem.swapOnce = function( rows, index ) {
var r1 = rows[Math.floor(Math.random() * (rows.length-2)) + 1];
var r2 = rows[Math.floor(Math.random() * (rows.length-2)) + 1];
var c1 = r1.cells[index];
r1.replaceChild(r2.cells[index], c1);
if(index == 0)
r2.insertBefore(c1, r2.cells[0]);
else
r2.appendChild(c1);
}
Mem.getModeDiv = function( index ) {
var r = "\
<span style='width:260px; text-align:right; padding: 0px 0px 2px 10px; letter-spacing:2px;\
border-left: solid #ccc 1px; \
border-bottom: solid #ccc 1px;'>\
";
var modes = [["flashcard mode", "return Mem.flashcardMode(this)"], ["matching mode", "return Mem.startMatching(this)"]];
for(var x=0; x<modes.length; x++) {
if( x > 0 ) r += " | ";
if(index == x)
r += "<b>" + modes[x][0] + "</b>";
else
r += "<a style='color:#aaa;' href='#' onclick=\"" + modes[x][1] + "\">" + modes[x][0] + "</a>";
}
r += "</span>";
return r;
}
Mem.getOptions = function() {
return "\
<div style='display:none; line-height:17px; margin:27px 6px 4px 6px; padding: 3px 4px 4px 20px; border:dashed #fc0 2px;' id=optionsBox>\
<a style='float:right; margin-top:-7px; font-size:9px;' href='#' onClick='return Mem.hideOptions(this)'>Hide Options</a>\
- <a target='_blank' href='http://memorizable.com/Help'>Help</a>\
- <a onclick='return Mem.startOver(this)' href='#'>Restart</a>\
- <a onclick='return Mem.close(this)' href='#'>Cancel</a>\
<br>\
- <a target='_blank' href='http://memorizable.com/About_Memorizable_Tables'>About Memorizable Tables</a>\
</div>\
";
}
Mem.setT = function(node) {
// Return current, if no change
if(! node)
return this.t;
// Remember last, for restoreTBody
if(( typeof( Mem.t ) == 'object'))
Mem.lastT = Mem.t;
// Climb up parent until we find table
while( ! node.isMem )
node = node.parentNode;
this.t = node;
return node;
}
Mem.lookupT = function(nodex) {
// Climb up parent until we find table
while(! nodex.isMem)
nodex = nodex.parentNode;
return nodex;
}
Mem.restoreTBody = function() {
Mem.t = Mem.lastT;
}
Mem.restore = function() {
var orig = Mem.t.s.tbodyBackup;
Mem.t.replaceChild( orig, Mem.t.tBodies[0] );
Mem.t = orig.parentNode;
// Whipe out ref to backup
Mem.t.s.tbodyBackup = null;
}
Mem.addRowsFromBackup = function() {
var t = this.t;
var rows = t.rows;
// Delete rows - except top and bottom
var length = rows.length;
for(var x=1; x<=length-2; x++)
t.tBodies[0].removeChild( rows[length - (x+1)] );
// Make copies from backup, add them to table
var bak = t.s.tbodyBackup.cloneNode( true );
var backupRows = bak.getElementsByTagName('tr');
var length = backupRows.length;
for(var x=1; x<length; x++)
t.tBodies[0].insertBefore( backupRows[1], rows[rows.length-1] );
}
Mem.glow = function(cycles, color, glowDiv, endColor) {
// Remember table
if(!glowDiv) {
glowDiv = this.tChile('directionsDiv');
// Do nothing if already going
if(glowDiv.cycles >= 1)
return;
}
glowDiv.cycles = cycles;
if(!endColor)
endColor = "#fff";
// Set end color to cell
glowDiv.endColor = endColor;
var glowLevel = color == "green" ? 35 : 0;
var glowIncrement = color == "red" ? 8 : 2;
if(color == "green") glowIncrement = 1;
var myInterval = window.setInterval(function () {
// Stop if cycles over
if(glowDiv.cycles <= 0) {
clearInterval(myInterval);
return;
}
// Change level
glowLevel += glowIncrement;
// Go darker
if(glowLevel < 0) {
glowIncrement = 2;
glowLevel += glowIncrement;
// If this is the end, set it to the end color
if(--glowDiv.cycles == 0) {
glowDiv.style.background = glowDiv.endColor;
return;
}
}
// Go lighter
if(glowLevel > 44) {
glowIncrement = -2;
glowLevel += glowIncrement;
if(glowDiv.cycles == 1) {
glowIncrement = color == "red" ? -6 : -1;
if(color == "green") glowIncrement = -6;
}
}
if(color == "red")
Mem.glowColor(glowDiv, glowLevel, 180, 1, -2, -2);
else if(color == "green")
Mem.glowColor(glowDiv, glowLevel, 255, -3, 0, -5);
else if(color == "finished")
Mem.glowColor(glowDiv, glowLevel, 255, -2, 0, -4);
else // Orange
Mem.glowColor(glowDiv, glowLevel, 255, 0, -1, -4);
}, 43);
}
Mem.glowColor = function(glowDiv, glowLevel, start, r, g, b) {
glowDiv.style.background = "rgb(" + (start+glowLevel*r) + "," + (start+glowLevel*g) + "," + (start+glowLevel*b) + ")";
}
Mem.chile = function(root, idName) {
var maybe = root.getElementsByTagName( '*' );
for(var x=0; x<maybe.length; x++)
if( maybe[x].id == idName )
return maybe[x];
}
Mem.tChile = function(idName) {
return this.chile(this.t, idName);
}
Mem.flashcardMode = function(node) {
Mem.setT(node);
return Mem.start( Mem.t.getElementsByTagName('a')[Mem.t.s.column] );
}
function trim( s ) {
return s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}
function byid( key ) {
return document.getElementById( key );
}
Mem.addEvent( document, "keydown", Mem.keyWasPressed );
|''URL:''|http://mptw.tiddlyspot.com/|
|''Description:''|a tiddlywiki distribution and plugins|
|''Author:''|SimonBaird|
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|show content in nest-able sliding/floating panels, without creating separate tiddlers for each panel's content|
!!!!!Documentation
>see [[NestedSlidersPluginInfo]]
!!!!!Configuration
<<<
<<option chkFloatingSlidersAnimate>> allow floating sliders to animate when opening/closing
>Note: This setting can cause 'clipping' problems in some versions of InternetExplorer.
>In addition, for floating slider animation to occur you must also allow animation in general (see [[AdvancedOptions]]).
<<<
!!!!!Revisions
<<<
2008.11.15 - 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class). In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
|please see [[NestedSlidersPluginInfo]] for additional revision details|
2005.11.03 - 1.0.0 initial public release. Thanks to RodneyGomes, GeoffSlocock, and PaulPetterson for suggestions and experiments.
<<<
!!!!!Code
***/
//{{{
version.extensions.NestedSlidersPlugin= {major: 2, minor: 4, revision: 9, date: new Date(2008,11,15)};
// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkFloatingSlidersAnimate===undefined)
config.options.chkFloatingSlidersAnimate=false; // avoid clipping problems in IE
// 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");
// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
window.removeCookie=function(name) {
document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;';
}
}
config.formatters.push( {
name: "nestedSliders",
match: "\\n?\\+{3}",
terminator: "\\s*\\={3}\\n?",
lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\@\\[\\>]*\\^)?)?(\\*)?(\\@)?(?:\\{\\{([\\w]+[\\s\\w]*)\\{)?(\\[[^\\]]*\\])?(\\[[^\\]]*\\])?(?:\\}{3})?(\\#[^:]*\\:)?(\\>)?(\\.\\.\\.)?\\s*",
handler: function(w)
{
lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
{
var defopen=lookaheadMatch[1];
var cookiename=lookaheadMatch[2];
var header=lookaheadMatch[3];
var panelwidth=lookaheadMatch[4];
var transient=lookaheadMatch[5];
var hover=lookaheadMatch[6];
var buttonClass=lookaheadMatch[7];
var label=lookaheadMatch[8];
var openlabel=lookaheadMatch[9];
var panelID=lookaheadMatch[10];
var blockquote=lookaheadMatch[11];
var deferred=lookaheadMatch[12];
// location for rendering button and panel
var place=w.output;
// default to closed, no cookie, no accesskey, no alternate text/tip
var show="none"; var cookie=""; var key="";
var closedtext=">"; var closedtip="";
var openedtext="<"; var openedtip="";
// extra "+", default to open
if (defopen) show="block";
// cookie, use saved open/closed state
if (cookiename) {
cookie=cookiename.trim().slice(1,-1);
cookie="chkSlider"+cookie;
if (config.options[cookie]==undefined)
{ config.options[cookie] = (show=="block") }
show=config.options[cookie]?"block":"none";
}
// parse label/tooltip/accesskey: [label=X|tooltip]
if (label) {
var parts=label.trim().slice(1,-1).split("|");
closedtext=parts.shift();
if (closedtext.substr(closedtext.length-2,1)=="=")
{ key=closedtext.substr(closedtext.length-1,1); closedtext=closedtext.slice(0,-2); }
openedtext=closedtext;
if (parts.length) closedtip=openedtip=parts.join("|");
else { closedtip="show "+closedtext; openedtip="hide "+closedtext; }
}
// parse alternate label/tooltip: [label|tooltip]
if (openlabel) {
var parts=openlabel.trim().slice(1,-1).split("|");
openedtext=parts.shift();
if (parts.length) openedtip=parts.join("|");
else openedtip="hide "+openedtext;
}
var title=show=='block'?openedtext:closedtext;
var tooltip=show=='block'?openedtip:closedtip;
// create the button
if (header) { // use "Hn" header format instead of button/link
var lvl=(header.length>5)?5:header.length;
var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,buttonClass,title);
btn.onclick=onClickNestedSlider;
btn.setAttribute("href","javascript:;");
btn.setAttribute("title",tooltip);
}
else
var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,buttonClass);
btn.innerHTML=title; // enables use of HTML entities in label
// set extra button attributes
btn.setAttribute("closedtext",closedtext);
btn.setAttribute("closedtip",closedtip);
btn.setAttribute("openedtext",openedtext);
btn.setAttribute("openedtip",openedtip);
btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
btn.defOpen=defopen!=null; // save default open/closed state (boolean)
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
}
btn.setAttribute("hover",hover?"true":"false");
btn.onmouseover=function(ev) {
// optional 'open on hover' handling
if (this.getAttribute("hover")=="true" && this.sliderPanel.style.display=='none') {
document.onclick.call(document,ev); // close transients
onClickNestedSlider(ev); // open this slider
}
// mouseover on button aligns floater position with button
if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this,this.sliderPanel);
}
// create slider panel
var panelClass=panelwidth?"floatingPanel":"sliderPanel";
if (panelID) panelID=panelID.slice(1,-1); // trim off delimiters
var panel=createTiddlyElement(place,"div",panelID,panelClass,null);
panel.button = btn; // so the slider panel know which button it belongs to
btn.sliderPanel=panel; // so the button knows which slider panel it belongs to
panel.defaultPanelWidth=(panelwidth && panelwidth.length>2)?panelwidth.slice(1,-1):"";
panel.setAttribute("transient",transient=="*"?"true":"false");
panel.style.display = show;
panel.style.width=panel.defaultPanelWidth;
panel.onmouseover=function(event) // mouseover on panel aligns floater position with button
{ if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this.button,this); }
// render slider (or defer until shown)
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
if ((show=="block")||!deferred) {
// render now if panel is supposed to be shown or NOT deferred rendering
w.subWikify(blockquote?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
// align floater position with button
if (window.adjustSliderPos) window.adjustSliderPos(place,btn,panel);
}
else {
var src = w.source.substr(w.nextMatch);
var endpos=findMatchingDelimiter(src,"+++","===");
panel.setAttribute("raw",src.substr(0,endpos));
panel.setAttribute("blockquote",blockquote?"true":"false");
panel.setAttribute("rendered","false");
w.nextMatch += endpos+3;
if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
}
}
}
}
)
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);
while (theTarget && theTarget.sliderPanel==undefined) theTarget=theTarget.parentNode;
if (!theTarget) return false;
var theSlider = theTarget.sliderPanel;
var isOpen = theSlider.style.display!="none";
// if SHIFT-CLICK, dock panel first (see [[MoveablePanelPlugin]])
if (e.shiftKey && config.macros.moveablePanel) config.macros.moveablePanel.dock(theSlider,e);
// toggle label
theTarget.innerHTML=isOpen?theTarget.getAttribute("closedText"):theTarget.getAttribute("openedText");
// toggle tooltip
theTarget.setAttribute("title",isOpen?theTarget.getAttribute("closedTip"):theTarget.getAttribute("openedTip"));
// deferred rendering (if needed)
if (theSlider.getAttribute("rendered")=="false") {
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 && (!hasClass(theSlider,'floatingPanel') || config.options.chkFloatingSlidersAnimate))
anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
else
theSlider.style.display = isOpen ? "none" : "block";
// reset to default width (might have been changed via plugin code)
theSlider.style.width=theSlider.defaultPanelWidth;
// align floater panel position with target button
if (!isOpen && window.adjustSliderPos) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider);
// 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" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")
{ try{ ctrls[c].focus(); } catch(err){;} break; }
}
}
var cookie=theTarget.sliderCookie;
if (cookie && cookie.length) {
config.options[cookie]=!isOpen;
if (config.options[cookie]!=theTarget.defOpen) window.saveOptionCookie(cookie);
else window.removeCookie(cookie); // remove cookie if slider is in default display state
}
// prevent SHIFT-CLICK from being processed by browser (opens blank window... yuck!)
// prevent clicks *within* a slider button from being processed by browser
// but allow plain click to bubble up to page background (to close transients, if any)
if (e.shiftKey || theTarget!=resolveTarget(e))
{ e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); }
Popup.remove(); // close open popup (if any)
return false;
}
//}}}
//{{{
// click in document background closes transient panels
document.nestedSliders_savedOnClick=document.onclick;
document.onclick=function(ev) { if (!ev) var ev=window.event; var target=resolveTarget(ev);
if (document.nestedSliders_savedOnClick)
var retval=document.nestedSliders_savedOnClick.apply(this,arguments);
// if click was inside a popup... leave transient panels alone
var p=target; while (p) if (hasClass(p,"popup")) break; else p=p.parentNode;
if (p) return retval;
// if click was inside transient panel (or something contained by a transient panel), leave it alone
var p=target; while (p) {
if ((hasClass(p,"floatingPanel")||hasClass(p,"sliderPanel"))&&p.getAttribute("transient")=="true") break;
p=p.parentNode;
}
if (p) return retval;
// otherwise, find and close all transient panels...
var all=document.all?document.all:document.getElementsByTagName("DIV");
for (var i=0; i<all.length; i++) {
// if it is not a transient panel, or the click was on the button that opened this panel, don't close it.
if (all[i].getAttribute("transient")!="true" || all[i].button==target) continue;
// otherwise, if the panel is currently visible, close it by clicking it's button
if (all[i].style.display!="none") window.onClickNestedSlider({target:all[i].button})
if (!hasClass(all[i],"floatingPanel")&&!hasClass(all[i],"sliderPanel")) all[i].style.display="none";
}
return retval;
};
//}}}
//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
if (hasClass(panel,"floatingPanel") && !hasClass(panel,"undocked")) {
// see [[MoveablePanelPlugin]] for use of 'undocked'
var rightEdge=document.body.offsetWidth-1;
var panelWidth=panel.offsetWidth;
var left=0;
var top=btn.offsetHeight;
if (place.style.position=="relative" && findPosX(btn)+panelWidth>rightEdge) {
left-=findPosX(btn)+panelWidth-rightEdge; // shift panel relative to button
if (findPosX(btn)+left<0) left=-findPosX(btn); // stay within left edge
}
if (place.style.position!="relative") {
var left=findPosX(btn);
var top=findPosY(btn)+btn.offsetHeight;
var p=place; while (p && !hasClass(p,'floatingPanel')) p=p.parentNode;
if (p) { left-=findPosX(p); top-=findPosY(p); }
if (left+panelWidth>rightEdge) left=rightEdge-panelWidth;
if (left<0) left=0;
}
panel.style.left=left+"px"; panel.style.top=top+"px";
}
}
//}}}
//{{{
// TW2.1 and earlier:
// hijack Slider stop handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function()
{ this.coreStop.apply(this,arguments); this.element.style.overflow = "visible"; }
// TW2.2+
// hijack Morpher stop handler so sliderPanel/floatingPanel overflow is visible after animation has completed
if (version.major+.1*version.minor+.01*version.revision>=2.2) {
Morpher.prototype.coreStop = Morpher.prototype.stop;
Morpher.prototype.stop = function() {
this.coreStop.apply(this,arguments);
var e=this.element;
if (hasClass(e,"sliderPanel")||hasClass(e,"floatingPanel")) {
// adjust panel overflow and position after animation
e.style.overflow = "visible";
if (window.adjustSliderPos) window.adjustSliderPos(e.parentNode,e.button,e);
}
};
}
//}}}
<!--{{{-->
<div class='header'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' force='true' tiddler='SiteSubtitle'></span>
<span class='siteMenu' refresh='content' force='true' tiddler='SiteMenu'></span>
<!-- horizontal MainMenu -->
<div id='topMenu' refresh='content' tiddler='MainMenu' style='margin-top:4px'></div>
<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
<div class='contents'>
<div id='sidebar'>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBar'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div id='storyMenu' class='storyMenu' refresh='content' force='true' tiddler='StoryMenu'></div>
</div>
<span style='display:none' macro='tiddler SiteStartup'></span>
<span style='display:none' macro='tiddler "TiddlyWiki keyboard shortcuts"'></span>
<!--}}}-->
/***
|<html><a name="Top"/></html>''Name:''|PartTiddlerPlugin|
|''Version:''|1.0.9 (2007-07-14)|
|''Source:''|http://tiddlywiki.abego-software.de/#PartTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.3|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Table of Content<html><a name="TOC"/></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Description',null, event)">Description, Syntax</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Applications',null, event)">Applications</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('LongTiddler',null, event)">Refering to Paragraphs of a Longer Tiddler</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Citation',null, event)">Citation Index</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('TableCells',null, event)">Creating "multi-line" Table Cells</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Tabs',null, event)">Creating Tabs</a></html>
** <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Sliders',null, event)">Using Sliders</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Revisions',null, event)">Revision History</a></html>
* <html><a href="javascript:;" onclick="window.scrollAnchorVisible('Code',null, event)">Code</a></html>
!Description<html><a name="Description"/></html>
With the {{{<part aPartName> ... </part>}}} feature you can structure your tiddler text into separate (named) parts.
Each part can be referenced as a "normal" tiddler, using the "//tiddlerName//''/''//partName//" syntax (e.g. "About/Features"). E.g. you may create links to the parts (e.g. {{{[[Quotes/BAX95]]}}} or {{{[[Hobbies|AboutMe/Hobbies]]}}}), use it in {{{<<tiddler...>>}}} or {{{<<tabs...>>}}} macros etc.
''Syntax:''
|>|''<part'' //partName// [''hidden''] ''>'' //any tiddler content// ''</part>''|
|//partName//|The name of the part. You may reference a part tiddler with the combined tiddler name "//nameOfContainerTidder//''/''//partName//. <br>If you use a partName containing spaces you need to quote it (e.g. {{{"Major Overview"}}} or {{{[[Shortcut List]]}}}).|
|''hidden''|When defined the content of the part is not displayed in the container tiddler. But when the part is explicitly referenced (e.g. in a {{{<<tiddler...>>}}} macro or in a link) the part's content is displayed.|
|<html><i>any tiddler content</i></html>|<html>The content of the part.<br>A part can have any content that a "normal" tiddler may have, e.g. you may use all the formattings and macros defined.</html>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!Applications<html><a name="Applications"/></html>
!!Refering to Paragraphs of a Longer Tiddler<html><a name="LongTiddler"/></html>
Assume you have written a long description in a tiddler and now you want to refer to the content of a certain paragraph in that tiddler (e.g. some definition.) Just wrap the text with a ''part'' block, give it a nice name, create a "pretty link" (like {{{[[Discussion Groups|Introduction/DiscussionGroups]]}}}) and you are done.
Notice this complements the approach to first writing a lot of small tiddlers and combine these tiddlers to one larger tiddler in a second step (e.g. using the {{{<<tiddler...>>}}} macro). Using the ''part'' feature you can first write a "classic" (longer) text that can be read "from top to bottom" and later "reuse" parts of this text for some more "non-linear" reading.
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!!Citation Index<html><a name="Citation"/></html>
Create a tiddler "Citations" that contains your "citations".
Wrap every citation with a part and a proper name.
''Example''
{{{
<part BAX98>Baxter, Ira D. et al: //Clone Detection Using Abstract Syntax Trees.//
in //Proc. ICSM//, 1998.</part>
<part BEL02>Bellon, Stefan: //Vergleich von Techniken zur Erkennung duplizierten Quellcodes.//
Thesis, Uni Stuttgart, 2002.</part>
<part DUC99>Ducasse, Stéfane et al: //A Language Independent Approach for Detecting Duplicated Code.//
in //Proc. ICSM//, 1999.</part>
}}}
You may now "cite" them just by using a pretty link like {{{[[Citations/BAX98]]}}} or even more pretty, like this {{{[[BAX98|Citations/BAX98]]}}}.
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!!Creating "multi-line" Table Cells<html><a name="TableCells"/></html>
You may have noticed that it is hard to create table cells with "multi-line" content. E.g. if you want to create a bullet list inside a table cell you cannot just write the bullet list
{{{
* Item 1
* Item 2
* Item 3
}}}
into a table cell (i.e. between the | ... | bars) because every bullet item must start in a new line but all cells of a table row must be in one line.
Using the ''part'' feature this problem can be solved. Just create a hidden part that contains the cells content and use a {{{<<tiddler >>}}} macro to include its content in the table's cell.
''Example''
{{{
|!Subject|!Items|
|subject1|<<tiddler ./Cell1>>|
|subject2|<<tiddler ./Cell2>>|
<part Cell1 hidden>
* Item 1
* Item 2
* Item 3
</part>
...
}}}
Notice that inside the {{{<<tiddler ...>>}}} macro you may refer to the "current tiddler" using the ".".
BTW: The same approach can be used to create bullet lists with items that contain more than one line.
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!!Creating Tabs<html><a name="Tabs"/></html>
The build-in {{{<<tabs ...>>}}} macro requires that you defined an additional tiddler for every tab it displays. When you want to have "nested" tabs you need to define a tiddler for the "main tab" and one for every tab it contains. I.e. the definition of a set of tabs that is visually displayed at one place is distributed across multiple tiddlers.
With the ''part'' feature you can put the complete definition in one tiddler, making it easier to keep an overview and maintain the tab sets.
''Example''
The standard tabs at the sidebar are defined by the following eight tiddlers:
* SideBarTabs
* TabAll
* TabMore
* TabMoreMissing
* TabMoreOrphans
* TabMoreShadowed
* TabTags
* TabTimeline
Instead of these eight tiddlers one could define the following SideBarTabs tiddler that uses the ''part'' feature:
{{{
<<tabs txtMainTab
Timeline Timeline SideBarTabs/Timeline
All 'All tiddlers' SideBarTabs/All
Tags 'All tags' SideBarTabs/Tags
More 'More lists' SideBarTabs/More>>
<part Timeline hidden><<timeline>></part>
<part All hidden><<list all>></part>
<part Tags hidden><<allTags>></part>
<part More hidden><<tabs txtMoreTab
Missing 'Missing tiddlers' SideBarTabs/Missing
Orphans 'Orphaned tiddlers' SideBarTabs/Orphans
Shadowed 'Shadowed tiddlers' SideBarTabs/Shadowed>></part>
<part Missing hidden><<list missing>></part>
<part Orphans hidden><<list orphans>></part>
<part Shadowed hidden><<list shadowed>></part>
}}}
Notice that you can easily "overwrite" individual parts in separate tiddlers that have the full name of the part.
E.g. if you don't like the classic timeline tab but only want to see the 100 most recent tiddlers you could create a tiddler "~SideBarTabs/Timeline" with the following content:
{{{
<<forEachTiddler
sortBy 'tiddler.modified' descending
write '(index < 100) ? "* [["+tiddler.title+"]]\n":""'>>
}}}
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!!Using Sliders<html><a name="Sliders"/></html>
Very similar to the build-in {{{<<tabs ...>>}}} macro (see above) the {{{<<slider ...>>}}} macro requires that you defined an additional tiddler that holds the content "to be slid". You can avoid creating this extra tiddler by using the ''part'' feature
''Example''
In a tiddler "About" we may use the slider to show some details that are documented in the tiddler's "Details" part.
{{{
...
<<slider chkAboutDetails About/Details details "Click here to see more details">>
<part Details hidden>
To give you a better overview ...
</part>
...
}}}
Notice that putting the content of the slider into the slider's tiddler also has an extra benefit: When you decide you need to edit the content of the slider you can just doubleclick the content, the tiddler opens for editing and you can directly start editing the content (in the part section). In the "old" approach you would doubleclick the tiddler, see that the slider is using tiddler X, have to look for the tiddler X and can finally open it for editing. So using the ''part'' approach results in a much short workflow.
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!Revision history<html><a name="Revisions"/></html>
* v1.0.9 (2007-07-14)
** Bugfix: Error when using the SideBarTabs example and switching between "More" and "Shadow". Thanks to cmari for reporting the issue.
* v1.0.8 (2007-06-16)
** Speeding up display of tiddlers containing multiple pard definitions. Thanks to Paco Rivière for reporting the issue.
** Support "./partName" syntax inside <<tabs ...>> macro
* v1.0.7 (2007-03-07)
** Bugfix: <<tiddler "./partName">> does not always render correctly after a refresh (e.g. like it happens when using the "Include" plugin). Thanks to Morris Gray for reporting the bug.
* v1.0.6 (2006-11-07)
** Bugfix: cannot edit tiddler when UploadPlugin by Bidix is installed. Thanks to José Luis González Castro for reporting the bug.
* v1.0.5 (2006-03-02)
** Bugfix: Example with multi-line table cells does not work in IE6. Thanks to Paulo Soares for reporting the bug.
* v1.0.4 (2006-02-28)
** Bugfix: Shadow tiddlers cannot be edited (in TW 2.0.6). Thanks to Torsten Vanek for reporting the bug.
* v1.0.3 (2006-02-26)
** Adapt code to newly introduced Tiddler.prototype.isReadOnly() function (in TW 2.0.6). Thanks to Paulo Soares for reporting the problem.
* v1.0.2 (2006-02-05)
** Also allow other macros than the "tiddler" macro use the "." in the part reference (to refer to "this" tiddler)
* v1.0.1 (2006-01-27)
** Added Table of Content for plugin documentation. Thanks to RichCarrillo for suggesting.
** Bugfix: newReminder plugin does not work when PartTiddler is installed. Thanks to PauloSoares for reporting.
* v1.0.0 (2006-01-25)
** initial version
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!Code<html><a name="Code"/></html>
<html><sub><a href="javascript:;" onclick="window.scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
***/
//{{{
//============================================================================
// PartTiddlerPlugin
// Ensure that the PartTiddler Plugin is only installed once.
//
if (!version.extensions.PartTiddlerPlugin) {
version.extensions.PartTiddlerPlugin = {
major: 1, minor: 0, revision: 9,
date: new Date(2007, 6, 14),
type: 'plugin',
source: "http://tiddlywiki.abego-software.de/#PartTiddlerPlugin"
};
if (!window.abego) window.abego = {};
if (version.major < 2) alertAndThrow("PartTiddlerPlugin requires TiddlyWiki 2.0 or newer.");
//============================================================================
// Common Helpers
// Looks for the next newline, starting at the index-th char of text.
//
// If there are only whitespaces between index and the newline
// the index behind the newline is returned,
// otherwise (or when no newline is found) index is returned.
//
var skipEmptyEndOfLine = function(text, index) {
var re = /(\n|[^\s])/g;
re.lastIndex = index;
var result = re.exec(text);
return (result && text.charAt(result.index) == '\n')
? result.index+1
: index;
}
//============================================================================
// Constants
var partEndOrStartTagRE = /(<\/part>)|(<part(?:\s+)((?:[^>])+)>)/mg;
var partEndTagREString = "<\\/part>";
var partEndTagString = "</part>";
//============================================================================
// Plugin Specific Helpers
// Parse the parameters inside a <part ...> tag and return the result.
//
// @return [may be null] {partName: ..., isHidden: ...}
//
var parseStartTagParams = function(paramText) {
var params = paramText.readMacroParams();
if (params.length == 0 || params[0].length == 0) return null;
var name = params[0];
var paramsIndex = 1;
var hidden = false;
if (paramsIndex < params.length) {
hidden = params[paramsIndex] == "hidden";
paramsIndex++;
}
return {
partName: name,
isHidden: hidden
};
}
// Returns the match to the next (end or start) part tag in the text,
// starting the search at startIndex.
//
// When no such tag is found null is returned, otherwise a "Match" is returned:
// [0]: full match
// [1]: matched "end" tag (or null when no end tag match)
// [2]: matched "start" tag (or null when no start tag match)
// [3]: content of start tag (or null if no start tag match)
//
var findNextPartEndOrStartTagMatch = function(text, startIndex) {
var re = new RegExp(partEndOrStartTagRE);
re.lastIndex = startIndex;
var match = re.exec(text);
return match;
}
//============================================================================
// Formatter
// Process the <part ...> ... </part> starting at (w.source, w.matchStart) for formatting.
//
// @return true if a complete part section (including the end tag) could be processed, false otherwise.
//
var handlePartSection = function(w) {
var tagMatch = findNextPartEndOrStartTagMatch(w.source, w.matchStart);
if (!tagMatch) return false;
if (tagMatch.index != w.matchStart || !tagMatch[2]) return false;
// Parse the start tag parameters
var arguments = parseStartTagParams(tagMatch[3]);
if (!arguments) return false;
// Continue processing
var startTagEndIndex = skipEmptyEndOfLine(w.source, tagMatch.index + tagMatch[0].length);
var endMatch = findNextPartEndOrStartTagMatch(w.source, startTagEndIndex);
if (endMatch && endMatch[1]) {
if (!arguments.isHidden) {
w.nextMatch = startTagEndIndex;
w.subWikify(w.output,partEndTagREString);
}
w.nextMatch = skipEmptyEndOfLine(w.source, endMatch.index + endMatch[0].length);
return true;
}
return false;
}
config.formatters.push( {
name: "part",
match: "<part\\s+[^>]+>",
handler: function(w) {
if (!handlePartSection(w)) {
w.outputText(w.output,w.matchStart,w.matchStart+w.matchLength);
}
}
} )
//============================================================================
// Extend "fetchTiddler" functionality to also recognize "part"s of tiddlers
// as tiddlers.
var currentParent = null; // used for the "." parent (e.g. in the "tiddler" macro)
// Return the match to the first <part ...> tag of the text that has the
// requrest partName.
//
// @return [may be null]
//
var findPartStartTagByName = function(text, partName) {
var i = 0;
while (true) {
var tagMatch = findNextPartEndOrStartTagMatch(text, i);
if (!tagMatch) return null;
if (tagMatch[2]) {
// Is start tag
// Check the name
var arguments = parseStartTagParams(tagMatch[3]);
if (arguments && arguments.partName == partName) {
return tagMatch;
}
}
i = tagMatch.index+tagMatch[0].length;
}
}
// Return the part "partName" of the given parentTiddler as a "readOnly" Tiddler
// object, using fullName as the Tiddler's title.
//
// All remaining properties of the new Tiddler (tags etc.) are inherited from
// the parentTiddler.
//
// @return [may be null]
//
var getPart = function(parentTiddler, partName, fullName) {
var text = parentTiddler.text;
var startTag = findPartStartTagByName(text, partName);
if (!startTag) return null;
var endIndexOfStartTag = skipEmptyEndOfLine(text, startTag.index+startTag[0].length);
var indexOfEndTag = text.indexOf(partEndTagString, endIndexOfStartTag);
if (indexOfEndTag >= 0) {
var partTiddlerText = text.substring(endIndexOfStartTag,indexOfEndTag);
var partTiddler = new Tiddler();
partTiddler.set(
fullName,
partTiddlerText,
parentTiddler.modifier,
parentTiddler.modified,
parentTiddler.tags,
parentTiddler.created);
partTiddler.abegoIsPartTiddler = true;
return partTiddler;
}
return null;
}
// Hijack the store.fetchTiddler to recognize the "part" addresses.
//
var hijackFetchTiddler = function() {
var oldFetchTiddler = store.fetchTiddler ;
store.fetchTiddler = function(title) {
var result = oldFetchTiddler.apply(this, arguments);
if (!result && title) {
var i = title.lastIndexOf('/');
if (i > 0) {
var parentName = title.substring(0, i);
var partName = title.substring(i+1);
var parent = (parentName == ".")
? store.resolveTiddler(currentParent)
: oldFetchTiddler.apply(this, [parentName]);
if (parent) {
return getPart(parent, partName, parent.title+"/"+partName);
}
}
}
return result;
};
};
// for debugging the plugin is not loaded through the systemConfig mechanism but via a script tag.
// At that point in the "store" is not yet defined. In that case hijackFetchTiddler through the restart function.
// Otherwise hijack now.
if (!store) {
var oldRestartFunc = restart;
window.restart = function() {
hijackFetchTiddler();
oldRestartFunc.apply(this,arguments);
};
} else
hijackFetchTiddler();
// The user must not edit a readOnly/partTiddler
//
config.commands.editTiddler.oldIsReadOnlyFunction = Tiddler.prototype.isReadOnly;
Tiddler.prototype.isReadOnly = function() {
// Tiddler.isReadOnly was introduced with TW 2.0.6.
// For older version we explicitly check the global readOnly flag
if (config.commands.editTiddler.oldIsReadOnlyFunction) {
if (config.commands.editTiddler.oldIsReadOnlyFunction.apply(this, arguments)) return true;
} else {
if (readOnly) return true;
}
return this.abegoIsPartTiddler;
}
config.commands.editTiddler.handler = function(event,src,title)
{
var t = store.getTiddler(title);
// Edit the tiddler if it either is not a tiddler (but a shadowTiddler)
// or the tiddler is not readOnly
if(!t || !t.abegoIsPartTiddler)
{
clearMessage();
story.displayTiddler(null,title,DEFAULT_EDIT_TEMPLATE);
story.focusTiddler(title,"text");
return false;
}
}
// To allow the "./partName" syntax in macros we need to hijack
// the invokeMacro to define the "currentParent" while it is running.
//
var oldInvokeMacro = window.invokeMacro;
function myInvokeMacro(place,macro,params,wikifier,tiddler) {
var oldCurrentParent = currentParent;
if (tiddler) currentParent = tiddler;
try {
oldInvokeMacro.apply(this, arguments);
} finally {
currentParent = oldCurrentParent;
}
}
window.invokeMacro = myInvokeMacro;
// To correctly support the "./partName" syntax while refreshing we need to hijack
// the config.refreshers.tiddlers to define the "currentParent" while it is running.
//
(function() {
var oldTiddlerRefresher= config.refreshers.tiddler;
config.refreshers.tiddler = function(e,changeList) {
var oldCurrentParent = currentParent;
try {
currentParent = e.getAttribute("tiddler");
return oldTiddlerRefresher.apply(this,arguments);
} finally {
currentParent = oldCurrentParent;
}
};
})();
// Support "./partName" syntax inside <<tabs ...>> macro
(function() {
var extendRelativeNames = function(e, title) {
var nodes = e.getElementsByTagName("a");
for(var i=0; i<nodes.length; i++) {
var node = nodes[i];
var s = node.getAttribute("content");
if (s && s.indexOf("./") == 0)
node.setAttribute("content",title+s.substr(1));
}
};
var oldHandler = config.macros.tabs.handler;
config.macros.tabs.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
var result = oldHandler.apply(this,arguments);
if (tiddler)
extendRelativeNames(place, tiddler.title);
return result;
};
})();
// Scroll the anchor anchorName in the viewer of the given tiddler visible.
// When no tiddler is defined use the tiddler of the target given event is used.
window.scrollAnchorVisible = function(anchorName, tiddler, evt) {
var tiddlerElem = null;
if (tiddler) {
tiddlerElem = document.getElementById(story.idPrefix + tiddler);
}
if (!tiddlerElem && evt) {
var target = resolveTarget(evt);
tiddlerElem = story.findContainingTiddler(target);
}
if (!tiddlerElem) return;
var children = tiddlerElem.getElementsByTagName("a");
for (var i = 0; i < children.length; i++) {
var child = children[i];
var name = child.getAttribute("name");
if (name == anchorName) {
var y = findPosY(child);
window.scrollTo(0,y);
return;
}
}
}
} // of "install only once"
//}}}
/***
<html><sub><a href="javascript:;" onclick="scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2006 ([[www.abego-software.de|http://www.abego-software.de]])
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
<html><sub><a href="javascript:;" onclick="scrollAnchorVisible('Top',null, event)">[Top]</sub></a></html>
***/
/***
|''Name:''|PasswordOptionPlugin|
|''Description:''|Extends TiddlyWiki options with non encrypted password option.|
|''Version:''|1.0.2|
|''Date:''|Apr 19, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#PasswordOptionPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.PasswordOptionPlugin = {
major: 1, minor: 0, revision: 2,
date: new Date("Apr 19, 2007"),
source: 'http://tiddlywiki.bidix.info/#PasswordOptionPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
coreVersion: '2.2.0 (Beta 5)'
};
config.macros.option.passwordCheckboxLabel = "Save this password on this computer";
config.macros.option.passwordInputType = "password"; // password | text
setStylesheet(".pasOptionInput {width: 11em;}\n","passwordInputTypeStyle");
merge(config.macros.option.types, {
'pas': {
elementType: "input",
valueField: "value",
eventName: "onkeyup",
className: "pasOptionInput",
typeValue: config.macros.option.passwordInputType,
create: function(place,type,opt,className,desc) {
// password field
config.macros.option.genericCreate(place,'pas',opt,className,desc);
// checkbox linked with this password "save this password on this computer"
config.macros.option.genericCreate(place,'chk','chk'+opt,className,desc);
// text savePasswordCheckboxLabel
place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));
},
onChange: config.macros.option.genericOnChange
}
});
merge(config.optionHandlers['chk'], {
get: function(name) {
// is there an option linked with this chk ?
var opt = name.substr(3);
if (config.options[opt])
saveOptionCookie(opt);
return config.options[name] ? "true" : "false";
}
});
merge(config.optionHandlers, {
'pas': {
get: function(name) {
if (config.options["chk"+name]) {
return encodeCookie(config.options[name].toString());
} else {
return "";
}
},
set: function(name,value) {config.options[name] = decodeCookie(value);}
}
});
// need to reload options to load passwordOptions
loadOptionsCookie();
/*
if (!config.options['pasPassword'])
config.options['pasPassword'] = '';
merge(config.optionsDesc,{
pasPassword: "Test password"
});
*/
//}}}
|''URL:''|http://bradleymeck.tiddlyspot.com/|
|''Description:''|Resources that are Ripe for the Picking|
|''Author:''|BradleyMeck|
/***
|''Name:''|~PopupMacro|
|''Version:''|1.0.0 (2006-05-09)|
|''Source:''|http://tw.lewcid.org/#PopupMacro|
|''Author:''|Saq Imtiaz|
|''Description:''|Create popups with custom content|
|''Documentation:''|[[PopupMacro Documentation|PopupMacroDocs]]|
|''~Requires:''|TW Version 2.0.8 or better|
***/
// /%
{{{
config.macros.popup = {};
config.macros.popup.arrow = (document.all?"▼":"▾");
config.macros.popup.handler = function(place,macroName,params,wikifier,paramString,theTiddler) {
if (!params[0] || !params[1])
{createTiddlyError(place,'missing macro parameters','missing label or content parameter');
return false;};
var label = params[0];
var source = (params[1]).replace(/\$\)\)/g,">>");
var nestedId = params[2]? params[2]: 'nestedpopup';
var onclick = function(event) {
if(!event){var event = window.event;}
var theTarget = resolveTarget(event);
var nested = (!isNested(theTarget));
if ((Popup.stack.length > 1)&&(nested==true)) {Popup.removeFrom(1);}
else if(Popup.stack.length > 0 && nested==false) {Popup.removeFrom(0);};
var theId = (nested==false)? "popup" : nestedId;
var popup = createTiddlyElement(document.body,"ol",theId,"popup",null);
Popup.stack.push({root: button, popup: popup});
wikify(source,popup);
Popup.show(popup,true);
event.cancelBubble = true;
if (event.stopPropagation) event.stopPropagation();
return false;
}
var button = createTiddlyButton(place, label+this.arrow,label, onclick, null);
};
window.isNested = function(e) {
while (e != null) {
var contentWrapper = document.getElementById("contentWrapper");
if (contentWrapper == e) return true;
e = e.parentNode;
}
return false;
};
setStylesheet(
".popup, .popup a, .popup a:visited {color: #fff;}\n"+
".popup a:hover {background: #014; color: #fff; border: none;}\n"+
".popup li , .popup ul, .popup ol {list-style:none !important; margin-left:0.3em !important; margin-right:0.3em; font-size:100%; padding-top:0.5px !important; padding:0px !important;}\n"+
"#nestedpopup {background:#2E5ADF; border: 1px solid #0331BF; margin-left:1em; }\n"+
"",
"CustomPopupStyles");
config.shadowTiddlers.PopupMacroDocs="The documentation is available [[here.|http://tw.lewcid.org/#PopupMacroDocs]]";
}}}
//%/
/***
|Name:|PrettyDatesPlugin|
|Description:|Provides a new date format ('pppp') that displays times such as '2 days ago'|
|Version:|1.0 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#PrettyDatesPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Notes
* If you want to you can rename this plugin. :) Some suggestions: LastUpdatedPlugin, RelativeDatesPlugin, SmartDatesPlugin, SexyDatesPlugin.
* Inspired by http://ejohn.org/files/pretty.js
***/
//{{{
Date.prototype.prettyDate = function() {
var diff = (((new Date()).getTime() - this.getTime()) / 1000);
var day_diff = Math.floor(diff / 86400);
if (isNaN(day_diff)) return "";
else if (diff < 0) return "in the future";
else if (diff < 60) return "just now";
else if (diff < 120) return "1 minute ago";
else if (diff < 3600) return Math.floor(diff/60) + " minutes ago";
else if (diff < 7200) return "1 hour ago";
else if (diff < 86400) return Math.floor(diff/3600) + " hours ago";
else if (day_diff == 1) return "Yesterday";
else if (day_diff < 7) return day_diff + " days ago";
else if (day_diff < 14) return "a week ago";
else if (day_diff < 31) return Math.ceil(day_diff/7) + " weeks ago";
else if (day_diff < 62) return "a month ago";
else if (day_diff < 365) return "about " + Math.ceil(day_diff/31) + " months ago";
else if (day_diff < 730) return "a year ago";
else return Math.ceil(day_diff/365) + " years ago";
}
Date.prototype.formatString_orig_mptw = Date.prototype.formatString;
Date.prototype.formatString = function(template) {
return this.formatString_orig_mptw(template).replace(/pppp/,this.prettyDate());
}
// for MPTW. otherwise edit your ViewTemplate as required.
// config.mptwDateFormat = 'pppp (DD/MM/YY)';
config.mptwDateFormat = 'pppp';
//}}}
/***
|Name|PreviewPlugin|
|Source|http://www.TiddlyTools.com/#PreviewPlugin|
|Documentation|http://www.TiddlyTools.com/#PreviewPluginInfo|
|Version|1.8.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|add key-by-key wikified preview to any textarea input field|
Provides key-by-key ''LIVE PREVIEW'' of //formatted// tiddler content as you type input into a textarea (multi-line) edit field.
!!!!!Documentation
>see [[PreviewPluginInfo]]
!!!!!Configuration
<<<
Automatically freeze preview updates when a tiddler takes more than <<option txtPreviewAutoFreeze>> milliseconds to render.
<<<
!!!!!Revisions
<<<
2008.01.08 [*.*.*] plugin size reduction: documentation moved to ...Info tiddler
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.11.18 [1.8.1] in config.commands.previewTiddler, changed alt command text to use character-based "psuedo-checkbox" instead of embedded html fragment
2007.09.27 [1.8.0] split TidIDE preview functionality into separate stand-alone plugin (see [[TidIDEPlugin]]).
|please see [[TidIDEPluginInfo]] for additional revision details|
2006.04.15 [0.5.0] Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
// // version info
//{{{
version.extensions.preview = {major: 1, minor: 8, revision: 1, date: new Date(2007,11,18)};
//}}}
// // macro definition
//{{{
if (config.options.txtPreviewAutoFreeze==undefined)
config.options.txtPreviewAutoFreeze=250; // limit (in milliseconds) for auto-freezing preview display
config.macros.preview = {
renderMsg: "rendering preview...",
timeoutMsg: " (> %0ms)",
freezeMsg: " - preview is frozen. Press [refresh] to re-display.",
handler: function(place,macroName,params) {
var hide=params[0]=="hide"; if (hide) params.shift();
var field=params[0];
var height=params[1]; if (!height) height=15;
var here=this.findContainingForm(place);
if (!here) here=story.findContainingTiddler(place);
if (!here) here=place.parentNode;
if (!here) here=place;
var elems=here.getElementsByTagName("textarea");
if (field) for (var e=0; e<elems.length; e++) // find matching textarea (by fieldname)
if (elems[e].getAttribute("edit")==field) var ta=elems[e];
else
if (elems.length) var ta=elems[elems.length-1]; // default to last rendered text area
if (!ta) {
var elems=here.getElementsByTagName("input");
if (field) for (var e=0; e<elems.length; e++) // find matching input field (by fieldname)
if (elems[e].getAttribute("edit")==field) var ta=elems[e];
else
if (elems.length) var ta=elems[elems.length-1]; // default to last rendered input field
}
if (!ta) return false; // no textarea or input field found... do nothing...
var id=(new Date().getTime()).toString()+Math.random(); // unique instance ID
ta.id=id+"_edit";
ta.setAttribute("previewid",id+"_preview");
ta.saved_onkeyup=ta.onkeyup;
ta.onkeyup=function(ev) {
if (this.saved_onkeyup) this.saved_onkeyup.apply(this,arguments);
config.macros.preview.render(this.id,this.getAttribute("previewid"));
}
var html=this.html.replace(/%previd%/g,id+"_preview")
html=html.replace(/%srcid%/g,id+"_edit");
html=html.replace(/%hide%/g,hide?"none":"block");
html=html.replace(/%limit%/g,config.options.txtPreviewAutoFreeze);
html=html.replace(/%frozen%/g,hide?"checked":"");
html=html.replace(/%height%/g,height);
html=html.replace(/%halfheight%/g,height/2);
createTiddlyElement(place,"span").innerHTML=html;
this.render(id+"_edit",id+"_preview");
},
findContainingForm: function(e) {
while (e && e.nodeName.toLowerCase()!="form") e=e.parentNode;
return e;
},
render: function(srcid,previd,force) {
var value=document.getElementById(srcid).value;
var panel=document.getElementById(previd);
var f=this.findContainingForm(panel);
if (!f || (f.freeze.checked && !force)) return;
var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
p.innerHTML="";
f.status.value=this.renderMsg;
var start=new Date();
wikify(value.replace(/\r/g,''),p);
var end=new Date();
this.renderDOM(previd);
this.renderHTML(previd);
f.status.value="elapsed: "+(end-start+1)+"ms";
// automatically suspend preview updates for slow rendering tiddlers
if (end-start+1>config.options.txtPreviewAutoFreeze) {
f.freeze.checked=true;
f.status.value+=this.timeoutMsg.format([config.options.txtPreviewAutoFreeze]);
}
if (f.freeze.checked) f.status.value+=this.freezeMsg;
},
renderDOM: function(id) {
var panel=document.getElementById(id);
var f=this.findContainingForm(panel); if (!f) return;
var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
var height=p.getAttribute("height");
p.style.height=((f.dom.checked||f.html.checked)?height/2:height)+"em";
if (f.dom.checked) d.value=this.getNodeTree(p,"| ");
if (!d.style||!h.style) return;
d.style.height=height/2+"em";
d.style.display=f.dom.checked?"inline":"none";
d.style.width=f.html.checked?"49.5%":"100%";
h.style.width=f.dom.checked?"49.5%":"100%";
},
renderHTML: function(id) {
var panel=document.getElementById(id);
var f=this.findContainingForm(panel); if (!f) return;
var p=panel.firstChild; var d=f.domview; var h=f.htmlview; if (!p||!d||!h) return;
var height=p.getAttribute("height");
p.style.height=((f.dom.checked||f.html.checked)?height/2:height)+"em";
if (f.html.checked) h.value=this.formatHTML(p.innerHTML);
if (!h.style||!d.style) return;
h.style.height=height/2+"em";
h.style.display=f.html.checked?"inline":"none";
h.style.width=f.dom.checked?"49.5%":"100%";
d.style.width=f.html.checked?"49.5%":"100%";
},
formatHTML: function(txt) {
if (config.browser.isIE) return txt; // BYPASS - 4/24/2006 due to IE hang problem. Will fix later...
var out="";
var indent="";
var level=0;
for (var i=0;i<txt.length;i++) {
var c=txt.substr(i,1);
if (c=="<") {
if (txt.substr(i+1,1)=="/") indent=indent.substr(0,indent.length-2);
out+="\n"+indent;
if (txt.substr(i+1,1)!="/" && txt.substr(i+1,3)!="br>" && txt.substr(i+1,2)!="p>" && txt.substr(i+1,3)!="hr>") indent+=" ";
}
out+=c;
if (c=="\n")
out+=indent;
if (c==">" && txt.substr(i+1,1)!="<")
out+="\n"+indent;
}
return out;
},
getNodeTree: function(theNode,theIndent,showPath,inline,thePrefix,thePath)
{
if (!theNode) return "";
if (!thePrefix) thePrefix="";
if (!thePath) thePath="";
var mquote='"'+(inline?"{{{":"");
var endmquote=(inline?"}}}":"")+'"';
// generate output for this node
var out = thePrefix;
if (showPath && thePath.length)
out += (inline?"//":"")+thePath.substr(1)+":"+(inline?"//":"")+"\r\n"+thePrefix;
if (theNode.className=="DOMViewer")
return out+'[DOMViewer]\r\n'; // avoid self-referential recursion
out += (inline?"''":"")+theNode.nodeName.toUpperCase()+(inline?"''":"");
if (theNode.nodeName=="#text")
out += ' '+mquote+theNode.nodeValue.replace(/\n/g,'\\n')+endmquote;
if (theNode.className)
out += ' class='+mquote+theNode.className+endmquote;
if (theNode.type)
out += ' type='+mquote+theNode.type+endmquote;
if (theNode.id)
out += ' id='+mquote+theNode.id+endmquote;
if (theNode.name)
out += " "+theNode.name+(theNode.value?"="+mquote+theNode.value+endmquote:"");
if (theNode.href)
out += ' href='+mquote+theNode.href+endmquote;
if (theNode.src)
out += ' src='+mquote+theNode.src+endmquote;
if (theNode.attributes && theNode.getAttribute("tiddlyLink")!=undefined)
out += ' tiddler='+mquote+theNode.getAttribute("tiddlyLink")+endmquote;
out += "\r\n";
// recursively generate output for child nodes
thePath=thePath+"."+theNode.nodeName.toLowerCase();
thePrefix=theIndent+thePrefix;
for (var i=0;i<theNode.childNodes.length;i++)
{
var thisChild=theNode.childNodes.item(i);
var theNum=(inline?"~~":"(")+(i+1)+(inline?"~~":")");
out += this.getNodeTree(thisChild,theIndent,showPath,inline,thePrefix,thePath+theNum);
}
return out;
},
html: " <form style='width:100%'><span id='%previd%' editID='%srcid%' style='display:%hide%'><div class='viewer' \
height='%height%' style='margin:0;margin-top:.5em;height:%height%em;overflow:auto;white-space:normal'> \
\
</div> \
<!-- DOM and HTML viewers --> \
<textarea name=domview cols=60 rows=12 wrap=off \
onfocus='this.select()' style='display:none;width:100%;height:%halfheight%em;'></textarea><!-- \
--><textarea name=htmlview cols=60 rows=12 wrap=off \
onfocus='this.select()' style='display:none;width:100%;height:%halfheight%em;'></textarea> \
<!-- status line, preview option checkboxes, run/refresh buttons --> \
<table width='100%' style='border:0;padding:0;margin:0'><tr style='border:0;padding:0;margin:0'> \
<td style='border:0;padding:0;margin:0'><!-- \
--><input type=text name=status style='padding:0;width:100%;' \
title='ELAPSED: time (in milliseconds) used to render tiddler content in preview display'><!-- \
--></td><td style='width:1%;border:0;padding:0;margin:0;'><!-- \
--><input type=text name=limit size='6' maxlength='6' style='padding:0;width:5em;text-align:center' \
value='%limit%ms' title='TIME LIMIT: maximum rendering time (in milliseconds) before auto-freezing preview' \
onfocus='this.select()' \
onchange='var val=this.value.replace(/[^0-9]/g,\"\"); if (!val.length) val=this.defaultValue; \
this.value=val+\"ms\"; config.options.txtPreviewAutoFreeze=val; saveOptionCookie(\"txtPreviewAutoFreeze\"); \
this.form.freeze.checked=false; config.macros.preview.render(\"%srcid%\",\"%previd%\",true);'><!-- \
--></td><td style='width:1%;border:0;padding:0;margin:0;'><!-- \
--><input type=text name=height size='4' maxlength='4' style='padding:0;width:4em;text-align:center' \
value='%height%em' title='HEIGHT: size (in \"ems\") of preview area, including controls' \
onfocus='this.select()' \
onchange='var val=this.value.replace(/[^0-9]/g,\"\"); if (!val.length) val=this.defaultValue; \
this.value=val+\"em\"; document.getElementById(\"%previd%\").firstChild.setAttribute(\"height\",val); \
config.macros.preview.render(\"%srcid%\",\"%previd%\",true)'><!-- \
--></td><td style='width:1%;border:0;padding:0;margin:0;text-align:right;white-space:nowrap'> \
<input type=checkbox name=dom style='display:inline;width:auto;margin:1px;' \
title='show Document Object Model (DOM) information' \
onclick='config.macros.preview.renderDOM(\"%previd%\");'>DOM \
<input type=checkbox name=html style='display:inline;width:auto;margin:1px;' \
title='show rendered HTML' \
onclick='config.macros.preview.renderHTML(\"%previd%\");'>HTML \
<input type=checkbox name=freeze style='display:inline;width:auto;margin:1px;' %frozen% \
title='do not update preview display as changes are made' \
onclick='var p=document.getElementById(\"%previd%\"); \
if (this.checked) this.form.status.value+=config.macros.preview.freezeMsg; \
else config.macros.preview.render(\"%srcid%\",\"%previd%\",true);'>freeze \
<input type=button style='display:inline;width:auto;' value='refresh' \
title='update preview display' \
onclick='config.macros.preview.render(\"%srcid%\",\"%previd%\",true)'> \
</td></tr></table> \
</span></form>"
}
//}}}
// // toolbar definition
//{{{
config.commands.previewTiddler = {
text: 'preview',
tooltip: 'show key-by-key preview',
text_alt: '\u221Apreview',
handler: function(event,src,title) {
var here=story.findContainingTiddler(src); if (!here) return;
var elems=here.getElementsByTagName("span");
for (var e=0; e<elems.length; e++) {
if (elems[e].getAttribute("editid")) {
var show=elems[e].style.display=="none";
src.innerHTML=show?this.text_alt:this.text;
elems[e].style.display=show?"block":"none";
config.macros.preview.findContainingForm(elems[e]).freeze.checked=!show;
if (show) config.macros.preview.render(elems[e].getAttribute("editid"),elems[e].id);
}
}
return false;
}
};
//}}}
|''URL:''|http://ptw.sourceforge.net/ptwe.html|
|''Description:''|BramChen's Extensions for TiddlyWiki|
|''Author:''|BramChen|
/***
|Name:|QuickOpenTagPlugin|
|Description:|Changes tag links to make it easier to open tags as tiddlers|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#QuickOpenTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
config.quickOpenTag = {
dropdownChar: (document.all ? "\u25bc" : "\u25be"), // the little one doesn't work in IE?
createTagButton: function(place,tag,excludeTiddler) {
// little hack so we can do this: <<tag PrettyTagName|RealTagName>>
var splitTag = tag.split("|");
var pretty = tag;
if (splitTag.length == 2) {
tag = splitTag[1];
pretty = splitTag[0];
}
var sp = createTiddlyElement(place,"span",null,"quickopentag");
createTiddlyText(createTiddlyLink(sp,tag,false),pretty);
var theTag = createTiddlyButton(sp,config.quickOpenTag.dropdownChar,
config.views.wikified.tag.tooltip.format([tag]),onClickTag);
theTag.setAttribute("tag",tag);
if (excludeTiddler)
theTag.setAttribute("tiddler",excludeTiddler);
return(theTag);
},
miniTagHandler: function(place,macroName,params,wikifier,paramString,tiddler) {
var tagged = store.getTaggedTiddlers(tiddler.title);
if (tagged.length > 0) {
var theTag = createTiddlyButton(place,config.quickOpenTag.dropdownChar,
config.views.wikified.tag.tooltip.format([tiddler.title]),onClickTag);
theTag.setAttribute("tag",tiddler.title);
theTag.className = "miniTag";
}
},
allTagsHandler: function(place,macroName,params) {
var tags = store.getTags(params[0]);
var filter = params[1]; // new feature
var ul = createTiddlyElement(place,"ul");
if(tags.length == 0)
createTiddlyElement(ul,"li",null,"listTitle",this.noTags);
for(var t=0; t<tags.length; t++) {
var title = tags[t][0];
if (!filter || (title.match(new RegExp('^'+filter)))) {
var info = getTiddlyLinkInfo(title);
var theListItem =createTiddlyElement(ul,"li");
var theLink = createTiddlyLink(theListItem,tags[t][0],true);
var theCount = " (" + tags[t][1] + ")";
theLink.appendChild(document.createTextNode(theCount));
var theDropDownBtn = createTiddlyButton(theListItem," " +
config.quickOpenTag.dropdownChar,this.tooltip.format([tags[t][0]]),onClickTag);
theDropDownBtn.setAttribute("tag",tags[t][0]);
}
}
},
// todo fix these up a bit
styles: [
"/*{{{*/",
"/* created by QuickOpenTagPlugin */",
".tagglyTagged .quickopentag, .tagged .quickopentag ",
" { margin-right:1.2em; border:1px solid #eee; padding:2px; padding-right:0px; padding-left:1px; }",
".quickopentag .tiddlyLink { padding:2px; padding-left:3px; }",
".quickopentag a.button { padding:1px; padding-left:2px; padding-right:2px;}",
"/* extra specificity to make it work right */",
"#displayArea .viewer .quickopentag a.button, ",
"#displayArea .viewer .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink ",
" { border:0px solid black; }",
"#displayArea .viewer .quickopentag a.button, ",
"#mainMenu .quickopentag a.button ",
" { margin-left:0px; padding-left:2px; }",
"#displayArea .viewer .quickopentag a.tiddlyLink, ",
"#mainMenu .quickopentag a.tiddlyLink ",
" { margin-right:0px; padding-right:0px; padding-left:0px; margin-left:0px; }",
"a.miniTag {font-size:150%;} ",
"#mainMenu .quickopentag a.button ",
" /* looks better in right justified main menus */",
" { margin-left:0px; padding-left:2px; margin-right:0px; padding-right:0px; }",
"#topMenu .quickopentag { padding:0px; margin:0px; border:0px; }",
"#topMenu .quickopentag .tiddlyLink { padding-right:1px; margin-right:0px; }",
"#topMenu .quickopentag .button { padding-left:1px; margin-left:0px; border:0px; }",
"/*}}}*/",
""].join("\n"),
init: function() {
// we fully replace these builtins. can't hijack them easily
window.createTagButton = this.createTagButton;
config.macros.allTags.handler = this.allTagsHandler;
config.macros.miniTag = { handler: this.miniTagHandler };
config.shadowTiddlers["QuickOpenTagStyles"] = this.styles;
store.addNotification("QuickOpenTagStyles",refreshStyles);
}
}
config.quickOpenTag.init();
//}}}
/***
|Name|RearrangeTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#RearrangeTiddlersPlugin|
|Version|2.0.0|
|Author|Eric Shulman|
|OriginalAuthor|Joe Raii|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.refreshTiddler|
|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
***/
//{{{
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 = document.getElementById(this.idPrefix + 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(p,false);
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;
}
};
//}}}
/***
|Name:|RenameTagsPlugin|
|Description:|Allows you to easily rename or delete tags across multiple tiddlers|
|Version:|3.0 ($Rev: 5501 $)|
|Date:|$Date: 2008-06-10 23:11:55 +1000 (Tue, 10 Jun 2008) $|
|Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {
prompts: {
rename: "Rename the tag '%0' to '%1' in %2 tidder%3?",
remove: "Remove the tag '%0' from %1 tidder%2?"
},
removeTag: function(tag,tiddlers) {
store.suspendNotifications();
for (var i=0;i<tiddlers.length;i++) {
store.setTiddlerTag(tiddlers[i].title,false,tag);
}
store.resumeNotifications();
store.notifyAll();
},
renameTag: function(oldTag,newTag,tiddlers) {
store.suspendNotifications();
for (var i=0;i<tiddlers.length;i++) {
store.setTiddlerTag(tiddlers[i].title,false,oldTag); // remove old
store.setTiddlerTag(tiddlers[i].title,true,newTag); // add new
}
store.resumeNotifications();
store.notifyAll();
},
storeMethods: {
saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,
saveTiddler: function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created) {
if (title != newTitle) {
var tagged = this.getTaggedTiddlers(title);
if (tagged.length > 0) {
// then we are renaming a tag
if (confirm(config.renameTags.prompts.rename.format([title,newTitle,tagged.length,tagged.length>1?"s":""])))
config.renameTags.renameTag(title,newTitle,tagged);
if (!this.tiddlerExists(title) && newBody == "")
// dont create unwanted tiddler
return null;
}
}
return this.saveTiddler_orig_renameTags(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created);
},
removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,
removeTiddler: function(title) {
var tagged = this.getTaggedTiddlers(title);
if (tagged.length > 0)
if (confirm(config.renameTags.prompts.remove.format([title,tagged.length,tagged.length>1?"s":""])))
config.renameTags.removeTag(title,tagged);
return this.removeTiddler_orig_renameTags(title);
}
},
init: function() {
merge(TiddlyWiki.prototype,this.storeMethods);
}
}
config.renameTags.init();
//}}}
/***
|Name|SaveAndReloadMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#SaveAndReloadMacro|
|Version|1.0|
|Requires|~TW2.x|
!Description:
Provides a button to save and reload TW. Useful if you are testing code and dont have AutoSave enabled.
!Demo:
{{{<<saveAndReload>>}}}<<saveAndReload>>
!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
!History:
*24-07-06: ver 1.0
!Code
***/
//{{{
config.macros.saveAndReload={};
config.macros.saveAndReload.handler= function(place,macroName,params,wikifier,paramString,tiddler)
{
var label = params[0]||"Save & Reload";
var tooltip = params[1]||"Save & reload";
createTiddlyButton(place,label,tooltip,this.onclick);
}
config.macros.saveAndReload.onclick= function()
{
saveChanges();
window.location.reload( false );
}
//}}}
/***
|Name|SaveAsPlugin|
|Source|http://www.TiddlyTools.com/#SaveAsPlugin|
|Documentation|http://www.TiddlyTools.com/#SaveAsPluginInfo|
|Version|2.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Save current document to a different path/filename|
This plugin automatically adds a 'save as' command to the TiddlyWiki 'backstage' menu that allows you to quickly create an exact copy of the current TiddlyWiki document. The plugin also defines a macro that you can use to place a "save as..." command link into your sidebar/mainmenu/any tiddler (or wherever you like).
>//Note: This plugin now supersedes [[NewDocumentPlugin]], which has been retired and is no longer being distributed. In addition, the HTML+CSS "snapshot" functionality previous provided by that plugin has been moved to a separate plugin. Please see [[SnapshotPlugin]] for additional information.//
!!!!!Documentation
<<<
see [[SaveAsPluginInfo]]
<<<
!!!!!Revisions
<<<
2008.09.29 [2.4.3] in getData(), convert existing TW file from UTF8 to Unicode before merging to correct handling of international characters and symbols.
| Please see [[SaveAsPluginInfo]] for additional revision details |
2006.02.03 [1.0.0] Created.
<<<
!!!!!Code
***/
//{{{
version.extensions.SaveAsPlugin= {major: 2, minor: 4, revision: 2, date: new Date(2008,9,28)};
config.macros.saveAs = {
label: "save as...",
labelparam: "label:",
prompt: "Save current document to a different path/file",
promptparam: "prompt:",
filePrompt: "Please select or enter a target path/filename",
targetparam: "target:",
defaultFilename: "new.html",
filenameparam: "filename:",
currfilekeyword: "here",
typeparam: "type:",
type_TW: "tw", type_PS: "ps", type_TX: "tx", type_NF: "nf", // file type tokens
type_map: { // map filetype param alternatives/abbreviations to token values
tiddlywiki:"tw", tw:"tw", wiki: "tw",
purestore: "ps", ps:"ps", store:"ps",
plaintext: "tx", tx:"tx", text: "tx",
newsfeed: "nf", nf:"nf", xml: "nf", rss:"nf"
},
replaceparam: "replace",
mergeparam: "merge",
quietparam: "quiet",
openparam: "open",
askParam: "ask",
askMsg: "Enter a tag filter (use * for all tiddlers, 'none' for blank document)",
emptyParam: "none",
confirmmsg: "Found %0 tiddlers matching\n\n'%1'\n\nPress OK to proceed",
mergeprompt: "%0\nalready contains tiddler definitions.\n"
+"\nPress OK to add new/revised tiddlers to current file contents."
+"\nPress Cancel to completely replace file contents",
mergestatus: "Merged %0 new/revised tiddlers and %1 existing tiddlers",
okmsg: "%0 tiddlers written to %1",
failmsg: "An error occurred while creating %1",
filter: "",
handler: function(place,macroName,params) {
if (params[0] && params[0].substr(0,this.labelparam.length)==this.labelparam)
var label=params.shift().substr(this.labelparam.length);
if (params[0] && params[0].substr(0,this.promptparam.length)==this.promptparam)
var prompt=params.shift().substr(this.promptparam.length);
if (params[0] && params[0].substr(0,this.targetparam.length)==this.targetparam)
var target=params.shift().substr(this.targetparam.length);
if (params[0] && params[0].substr(0,this.filenameparam.length)==this.filenameparam)
var filename=params.shift().substr(this.filenameparam.length);
if (params[0] && params[0].substr(0,this.typeparam.length)==this.typeparam)
var filetype=this.type_map[params.shift().substr(this.typeparam.length).toLowerCase()];
var q=(params[0] && params[0]==this.quietparam); if (q) params.shift();
var o=(params[0] && params[0]==this.replaceparam); if (o) params.shift();
var m=(params[0] && params[0]==this.mergeparam); if (m) params.shift();
var a=(params[0] && params[0]==this.openparam); if (a) params.shift();
var btn=createTiddlyButton(place,label||this.label,prompt||this.prompt,
function(){config.macros.saveAs.go(
this.getAttribute('target'),
this.getAttribute('filename'),
this.getAttribute('filetype'),
this.getAttribute('filter'),
this.getAttribute('quiet')=="true",
this.getAttribute('overwrite')=="true",
this.getAttribute('merge')=="true",
this.getAttribute('autoopen')=="true"); return false;}
);
if (target) btn.setAttribute("target",target);
if (filename) btn.setAttribute("filename",filename);
btn.setAttribute("filetype",filetype||this.type_TW);
btn.setAttribute("filter",params.join(" "));
btn.setAttribute("quiet",q?"true":"false");
btn.setAttribute("overwrite",o?"true":"false");
btn.setAttribute("merge",m?"true":"false");
btn.setAttribute("autoopen",a?"true":"false");
},
go: function(target,filename,filetype,filter,quiet,overwrite,merge,autoopen) {
var cm=config.messages; // abbreviation
var cms=config.macros.saveAs; // abbreviation
if (window.location.protocol!="file:") // make sure we are local
{ displayMessage(cm.notFileUrlError); return; }
// get tidders, confirm filtered results
var tids=cms.selectTiddlers(filter);
if (tids===false) return; // cancelled by user
if (cms.filter!=cms.emptyParam && cms.filter.length && !quiet)
if (!confirm(cms.confirmmsg.format([tids.length,cms.filter]))) return;
// get target path/filename
if (!filetype) filetype=this.type_TW;
target=target||cms.getTarget(filename,filetype==this.type_TX?'txt':'html');
if (!target) return; // cancelled by user
var link="file:///"+target.replace(/\\/g,'/');
var samefile=link==decodeURIComponent(window.location.href);
var p=getLocalPath(document.location.href);
if (samefile) {
if (config.options.chkSaveBackups) { var t=loadOriginal(p);if(t)saveBackup(p,t); }
if (config.options.chkGenerateAnRssFeed && saveRss instanceof Function) saveRss(p);
}
var notes="";
var total={val:0};
var out=this.assembleFile(target,filetype,tids,notes,quiet,overwrite,merge,total);
var ok=saveFile(target,out);
if (ok && autoopen) {
if (!samefile) window.open(link).focus();
else { store.setDirty(false); window.location.reload(); }
}
if (!quiet || !(ok && autoopen))
displayMessage((ok?this.okmsg:this.failmsg).format([total.val,target]),link);
},
selectTiddlers: function(filter) {
var cms=config.macros.saveAs; // abbreviation
cms.filter=filter||"";
if (filter==cms.emptyParam) return [];
if (!filter||!filter.length) return store.getTiddlers("title");
// get filtered tiddlers
if (filter==config.macros.saveAs.askParam) {
filter=prompt(config.macros.saveAs.askMsg,"");
if (!filter) return false; // cancelled by user
cms.filter=filter=="*"?"":filter;
if (filter=="*") return store.getTiddlers("title");
}
return store.filterTiddlers("[tag["+filter+"]]");
},
getTarget: function(defName,defExt) {
var cms=config.macros.saveAs; // abbreviation
// get new target path/filename
var newPath=getLocalPath(window.location.href);
var slashpos=newPath.lastIndexOf("/"); if (slashpos==-1) slashpos=newPath.lastIndexOf("\\");
if (slashpos!=-1) newPath=newPath.substr(0,slashpos+1); // trim filename
if (!defName||!defName.length) { // use current filename as default
var p=getLocalPath(window.location.href);
var s=p.lastIndexOf("/"); if (s==-1) s=p.lastIndexOf("\\");
if (s!=-1) defName=p.substr(s+1);
}
var defFilename=(defName||cms.defaultFilename).replace(/.html$/,'.'+defExt);
var target=cms.askForFilename(cms.filePrompt,newPath,defFilename,defExt);
if (!target) return; // cancelled by user
// if specified file does not include a path, assemble fully qualified path and filename
var slashpos=target.lastIndexOf("/"); if (slashpos==-1) slashpos=target.lastIndexOf("\\");
if (slashpos==-1) target=target+(defName||cms.defaultFilename).replace(/.html$/,'.'+defExt);
return target;
},
askForFilename: function(msg,path,file,defExt) {
if(window.Components) { // moz
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension=defExt||'html';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
}
catch(e) { alert('error during local file access: '+e.toString()) }
}
else { // IE
try { // XP/Vista only
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
s.FilterIndex=(defExt=='txt')?2:3; // default to HTML files;
s.InitialDir=path;
s.FileName=file;
if (s.showOpen()) var result=s.FileName;
}
catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
}
return result;
},
plainTextHeader:
'// Source'+':\n//\t%0\n'
+'// Title:\n//\t%1\n'
+'// Subtitle:\n//\t%2\n'
+'// Created:\n//\t%3 by %4\n'
+'// Application:\n//\tTiddlyWiki %5 / %6 %7\n',
plainTextTiddler:
'\n// ----- %0 (by %1 on %2) -----\n\n%3',
plainTextFooter:
'',
newsFeedHeader:
'<'+'?xml version="1.0"?'+'>\n'
+'<rss version="2.0">\n'
+'<channel>\n'
+'<title>%1</title>\n'
+'<link>%0</link>\n'
+'<description>%2</description>\n'
+'<language>en-us</language>\n'
+'<copyright>Copyright '+(new Date().getFullYear())+' %4</copyright>\n'
+'<pubDate>%3</pubDate>\n'
+'<lastBuildDate>%3</lastBuildDate>\n'
+'<docs>http://blogs.law.harvard.edu/tech/rss</docs>\n'
+'<generator>TiddlyWiki %5 / %6 %7</generator>\n',
newsFeedTiddler:
'\n%0\n',
newsFeedFooter:
'</channel></rss>',
pureStoreHeader:
'<html><body>'
+'<style type="text/css">'
+' #storeArea {display:block;margin:1em;}'
+' #storeArea div {padding:0.5em;margin:1em;border:2px solid black;height:10em;overflow:auto;}'
+' #pureStoreHeading {width:100%;text-align:left;background-color:#eeeeee;padding:1em;}'
+'</style>'
+'<div id="pureStoreHeading">'
+' TiddlyWiki "PureStore" export file<br>'
+' Source'+': <b>%0</b><br>'
+' Title: <b>%1</b><br>'
+' Subtitle: <b>%2</b><br>'
+' Created: <b>%3</b> by <b>%4</b><br>'
+' TiddlyWiki %5 / %6 %7<br>'
+' Notes:<hr><pre>%8</pre>'
+'</div>'
+'<div id="storeArea">',
pureStoreTiddler:
'%0\n%1',
pureStoreFooter:
'</div><!--POST-BODY-START-->\n<!--POST-BODY-END--></body></html>',
assembleFile: function(target,filetype,tids,notes,quiet,overwrite,merge,total) {
var revised="";
var now = new Date().toLocaleString();
var src=convertUnicodeToUTF8(document.location.href);
var title = convertUnicodeToUTF8(wikifyPlain("SiteTitle").htmlEncode());
var subtitle = convertUnicodeToUTF8(wikifyPlain("SiteSubtitle").htmlEncode());
var user = convertUnicodeToUTF8(config.options.txtUserName.htmlEncode());
var twver = version.major+"."+version.minor+"."+version.revision;
var v=version.extensions.SaveAsPlugin; var pver = v.major+"."+v.minor+"."+v.revision;
var headerargs=[src,title,subtitle,now,user,twver,"SaveAsPlugin",pver,notes];
switch (filetype) {
case this.type_TX: // plain text
var header=this.plainTextHeader.format(headerargs);
var footer=this.plainTextFooter;
break;
case this.type_NF: // news feed (XML)
headerargs[0]=store.getTiddlerText("SiteUrl","");
var header=this.newsFeedHeader.format(headerargs);
var footer=this.newsFeedFooter;
break;
case this.type_PS: // PureStore (no code)
var header=this.pureStoreHeader.format(headerargs);
var footer=this.pureStoreFooter;
break;
case this.type_TW: // full TiddlyWiki
default:
var currPath=getLocalPath(window.location.href);
var original=loadFile(currPath);
if (!original) { alert(config.messages.cantSaveError); return; }
var posDiv = locateStoreArea(original);
if (!posDiv) { alert(config.messages.invalidFileError.format([currPath])); return; }
var header = original.substr(0,posDiv[0]+startSaveArea.length)+"\n";
var footer = "\n"+original.substr(posDiv[1]);
break;
}
var out=this.getData(target,filetype,tids,quiet,overwrite,merge);
var revised = header+convertUnicodeToUTF8(out.join("\n"))+footer;
// if full TW, insert page title and language attr, and reset MARKUP blocks as needed...
if (filetype==this.type_TW) {
var newSiteTitle=convertUnicodeToUTF8(getPageTitle()).htmlEncode();
revised=revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
revised=updateLanguageAttribute(revised);
var titles=[]; for (var i=0; i<tids.length; i++) titles.push(tids[i].title);
revised=updateMarkupBlock(revised,"PRE-HEAD",
titles.contains("MarkupPreHead")? "MarkupPreHead" :null);
revised=updateMarkupBlock(revised,"POST-HEAD",
titles.contains("MarkupPostHead")?"MarkupPostHead":null);
revised=updateMarkupBlock(revised,"PRE-BODY",
titles.contains("MarkupPreBody")? "MarkupPreBody" :null);
revised=updateMarkupBlock(revised,"POST-SCRIPT",
titles.contains("MarkupPostBody")?"MarkupPostBody":null);
}
total.val=out.length;
return revised;
},
formatItem: function(s,f,t,u) {
if (f==this.type_TW) var r=s.getSaver().externalizeTiddler(s,t);
if (f==this.type_PS) var r=this.pureStoreTiddler.format([t.title,s.getSaver().externalizeTiddler(s,t)]);
if (f==this.type_NF) var r=this.newsFeedTiddler.format([t.saveToRss(u)]);
if (f==this.type_TX) var r=this.plainTextTiddler.format([t.title,t.modifier,t.modified.toLocaleString(),t.text]);
return r||"";
},
getData: function(target,filetype,tids,quiet,overwrite,merge) {
// output selected tiddlers and gather list of titles (for use with merge)
var out=[]; var titles=[];
var url=store.getTiddlerText("SiteUrl","");
for (var i=0; i<tids.length; i++) {
out.push(this.formatItem(store,filetype,tids[i],url));
titles.push(tids[i].title);
}
// if TW or PureStore format, ask to merge with existing tiddlers (if any)
if (filetype==this.type_TW || filetype==this.type_PS) {
if (overwrite) return out; // skip merge... forced overwrite
var text=loadFile(target);
if (text && text.length) {
var remoteStore=new TiddlyWiki();
if (remoteStore.importTiddlyWiki(convertUTF8ToUnicode(text))
&& (merge||confirm(this.mergeprompt.format([target])))) {
var existing=remoteStore.getTiddlers("title");
for (var i=0; i<existing.length; i++)
if (!titles.contains(existing[i].title))
out.push(this.formatItem(remoteStore,filetype,existing[i],url));
if (!quiet) displayMessage(this.mergestatus.format([tids.length,out.length-tids.length]));
}
}
}
return out;
}
};
//}}}
//{{{
// automatically add saveAs to backstage
config.tasks.saveAs = {
text: "saveAs",
tooltip: config.macros.saveAs.prompt,
action: function(){ clearMessage(); config.macros.saveAs.go(); }
}
config.backstageTasks.splice(config.backstageTasks.indexOf("save")+1,0,"saveAs");
//}}}
/***
|Name:|SaveCloseTiddlerPlugin|
|Description:|Provides two extra toolbar commands, saveCloseTiddler and cancelCloseTiddler|
|Version:|3.0 ($Rev: 5502 $)|
|Date:|$Date: 2008-06-10 23:31:39 +1000 (Tue, 10 Jun 2008) $|
|Source:|http://mptw.tiddlyspot.com/#SaveCloseTiddlerPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
To use these you must add them to the tool bar in your EditTemplate
***/
//{{{
merge(config.commands,{
saveCloseTiddler: {
text: 'done/close',
tooltip: 'Save changes to this tiddler and close it',
handler: function(ev,src,title) {
var closeTitle = title;
var newTitle = story.saveTiddler(title,ev.shiftKey);
if (newTitle)
closeTitle = newTitle;
return config.commands.closeTiddler.handler(ev,src,closeTitle);
}
},
cancelCloseTiddler: {
text: 'cancel/close',
tooltip: 'Undo changes to this tiddler and close it',
handler: function(ev,src,title) {
// the same as closeTiddler now actually
return config.commands.closeTiddler.handler(ev,src,title);
}
}
});
//}}}
/***
{{sectionTOC clear small floatright groupbox{Table of Contents:}}}
|Name|SectionLinksPlugin|
|Source|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Documentation|http://www.TiddlyTools.com/#SectionLinksPlugin|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|allow tiddler sections in TiddlyLinks to be used as anchor points|
This tweak extends the TiddlyLink and displayTiddler() processing so that section references in links can be used to auto-scroll to the indicated heading within a tiddler (i.e., the same 'anchor' behavior as {{{<a name="foo">}}} and {{{<a href="#foo">...</a>}}} when using HTML syntax).
!!!Usage
<<<
The TiddlyWiki core handling allows you to use the tiddler section syntax within the {{{<<tiddler>>}}} macro to //transclude// a subsection of one tiddler into another (e.g., {{{<<tiddler SomeTiddler##SomeSection>>}}}). However, if this syntax is used in a TiddlyLink (e.g., {{{[[SomeTiddler##SomeSection]]}}}), the core treates the entire reference as a link to a (non-existent) tiddler that includes the section reference in the tiddler title itself.
!!!!extended link syntax
This plugin modifies the core logic so that any {{{##SectionName}}} included in a tiddler link will be automatically removed //before// displaying the tiddler. Then, //after// the tiddler is rendered, the section reference is used to scroll (if needed) directly to that part of the tiddler so that the section heading appears at (or near) the top of the browser's display area.
!!!!"""<<sectionTOC>>""" macro
The plugin also adds a macro that generates a "Table of Contents"-style numbered-bullet list with links to all sections within the current tiddler. Simply place the following macro at the //end of the tiddler content// (or at least following all section headings):
{{{
<<sectionTOC>> or <<sectionTOC className>>
}}}
The macro must be placed at the end of the tiddler in order to locate the rendered section headings that precede it. By default, the macro's output is written directly in place of the embedded macro itself; however, as this would be displayed //following// the sections, it is normally not very useful by itself. To address this, you can embed a 'target element' at the desired output location within the tiddler content by using a //CSS class-wrapper// with any unique classname (default="sectionTOC"), like this:
{{{
{{sectionTOC{}}}
}}}
Then, when the {{{<<sectionTOC>>}}} macro is rendered, it will automatically find and write it's output into the indicated target element. In addition to the required //sectionTOC// classname, you can add any other CSS classes you want to the target element to apply extra styles. Also, the generated numbered list output will be inserted //following// any other wiki-formatted content you might include within the target element. For example, the following declaration has been embedded at the top of this plugin to create the "Table of Contents" display you see in the upper right corner of the rendered tiddler.
{{{
{{sectionTOC clear small floatright groupbox{Table of Contents:}}}
}}}
<<<
!!!Revisions
<<<
2009.01.18 [1.1.0] added {{{<<sectionTOC>>}}} macro to generate numbered-bullet links to sections of current tiddler
2009.01.06 [1.0.0] converted to stand-alone plugin
2008.10.14 [0.0.0] initial release (as [[CoreTweaks]] #784 - http://trac.tiddlywiki.org/ticket/784)
<<<
!!!Code
***/
//{{{
version.extensions.SectionLinksPlugin= {major: 1, minor: 1, revision: 0, date: new Date(2009,1,18)};
//}}}
/***
!!!!core hijacks
***/
//{{{
Story.prototype.scrollToSection = function(title,section) {
if (!title||!section) return; var t=this.getTiddler(title); if (!t) return null;
var elems=t.getElementsByTagName('*');
for (var i=0; i<elems.length; i++) { var e=elems[i];
if (!['H1','H2','H3','H4','H5'].contains(e.nodeName)) continue;
if (getPlainText(e).indexOf(section)!=-1) {
// if section heading is collapsed, click to expand it - see [[FoldHeadingsPlugin]]
if (hasClass(e,'foldable') && e.nextSibling.style.display=='none') e.onclick();
// scroll *after* tiddler animation
var delay=config.options.chkAnimate?config.animDuration+100:0;
setTimeout('window.scrollTo('+findPosX(e)+','+findPosY(e)+')',delay);
return e;
}
}
}
window.createTiddlyLink_sectionanchor=window.createTiddlyLink;
window.createTiddlyLink=function(place,title) {
var t=story.findContainingTiddler(place); var tid=t?t.getAttribute('tiddler'):'';
var parts=title.split(config.textPrimitives.sectionSeparator);
if (!parts[0].length) parts[0]=tid; // default to current tiddler for '##section' links
if (parts[1]) arguments[1]=parts[0]; // trim section from tiddler title
var btn=createTiddlyLink_sectionanchor.apply(this,arguments);
if (parts[1]) btn.setAttribute('section',parts[1]); // save section
return btn;
}
window.onClickTiddlerLink_sectionanchor=window.onClickTiddlerLink;
window.onClickTiddlerLink=function(ev) {
var e=ev||window.event; var target=resolveTarget(e); var title=null;
while (target!=null && title==null) {
title=target.getAttribute('tiddlyLink');
section=target.getAttribute('section');
target=target.parentNode;
}
var t=story.findContainingTiddler(target); var tid=t?t.getAttribute('tiddler'):'';
if (title!=tid||!section) onClickTiddlerLink_sectionanchor.apply(this,arguments); // avoid excess scrolling
story.scrollToSection(title,section);
return false;
}
Story.prototype.displayTiddler_sectionanchor=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler)
{
var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
var parts=title.split(config.textPrimitives.sectionSeparator);
if (parts[0].length && parts[1]) arguments[1]=parts[0]; // trim section from tiddler title
this.displayTiddler_sectionanchor.apply(this,arguments);
story.scrollToSection(parts[0],parts[1]);
}
config.formatterHelpers.isExternalLink_sectionanchor=config.formatterHelpers.isExternalLink;
config.formatterHelpers.isExternalLink=function(link) {
if (link.indexOf(config.textPrimitives.sectionSeparator)!=-1) return false;
return config.formatterHelpers.isExternalLink_sectionanchor.apply(this,arguments);
}
//}}}
/***
!!!!macro definition
***/
//{{{
config.macros.sectionTOC = {
targetClass: 'sectionTOC',
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var out=[];
var targetClass=params[0]||this.targetClass;
var t=story.findContainingTiddler(place); if (!t) return;
var elems=t.getElementsByTagName("*");
var level=5; // topmost heading level
for (var i=0; i<elems.length; i++) {
var link="[["+getPlainText(elems[i])+"|##"+getPlainText(elems[i])+"]]";
switch(elems[i].nodeName) {
case "H1": out.push("#"+link); level=1; break;
case "H2": out.push("##"+link); level=level<2?level:2; break;
case "H3": out.push("###"+link); level=level<3?level:3; break;
case "H4": out.push("####"+link); level=level<4?level:4; break;
case "H5": out.push("#####"+link); level=level<5?level:5; break;
default: if (hasClass(elems[i],targetClass)) var target=elems[i];
}
}
// trim excess bullet levels
if (level>1) for (var i=0; i<out.length; i++) out[i]=out[i].substr(level-1);
// render numbered list
wikify(out.join("\n"),target||place);
}
}
//}}}
/***
!!!Invoke macro
{{{
<<sectionTOC>>
}}}
***/
// //<<sectionTOC>>
/***
|Name|SetUserNamePlugin|
|Source|http://www.TiddlyTools.com/#SetUserNamePlugin|
|Version|1.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|prompt for TiddlyWiki username|
!!!!!Usage
<<<
{{{
<<setUserName force>>
}}}
This macro prompts for a new username if the default username ("YourName") is currently set. Use optional 'force' keyword to trigger a prompt even if username has already been set.
If you are using the default (shadow) EditTemplate definition, it will be updated to invoke this macro, via the following template syntax:
{{{
<span macro='setUserName'></span>
}}}
so that whenever a user attempts to edit/create a tiddler AND have not yet entered a username, they will be automatically prompted to enter a new username. If you are using a customized EditTemplate, you will need to edit it yourself to add the above.
<<<
!!!!!Revisions
<<<
2006.12.01 [1.0.0] initial release - converted from SetUserName inline script
<<<
!!!!!Code
***/
//{{{
version.extensions.setUserName= {major: 1, minor: 0, revision: 0, date: new Date(2006,12,1)};
config.macros.setUserName = {
msg: "Please set your username",
handler: function(place,macroName,params) {
// only prompt when needed or forced
var force=params[0]&¶ms[0].toLowerCase()=="force";
if (!force && (readOnly || config.options.txtUserName!="YourName")) return;
var opt="txtUserName";
var who=prompt(this.msg,config.options[opt]);
if (!who||!who.trim().length) return; // cancelled by user
config.options[opt]=who;
saveOptionCookie(opt);
config.macros.option.propagateOption(opt,"value",config.options[opt],"input");
}
}
// add trigger to default shadow EditTemplate (custom templates: add this by hand)
config.shadowTiddlers.EditTemplate+="<span macro='setUserName'></span>";
//}}}
/%
|Name|ShowPopup|
|Source|http://www.TiddlyTools.com/#ShowPopup|
|Version|1.1.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|transcluded html|
|Requires||
|Overrides||
|Description|display tiddler content in a TW popup|
usage: <<tiddler ShowPopup with: TiddlerName label tooltip buttonClass width popupClass>>
%/<html><a href="javascript:;" class="$4" title="$3" onclick="var p=Popup.create(this); if (!p) return; var t=store.getTiddlerText('$1'); if (!t) return; p.className+=' $6'; var d=createTiddlyElement(p,'div'); d.style.whiteSpace='normal'; d.style.width='$5'; d.style.padding='2px'; wikify(t,d); Popup.show(p,false); event.cancelBubble = true; if (event.stopPropagation) event.stopPropagation(); return(false);">$2</a></html>
/***
|Name|ShowUpdatesPlugin|
|Created by|SaqImtiaz|
|Version|0.2 |
|Requires|~TW2.x|
!!!Description:
Allows you to list tiddlers that have changed since the users last visit. You can list only all changed tiddlers, or filter them to only show tiddlers that have or do not have a specific tag. By default a simple list of the titles of changed tiddlers is created. However, using an extremely versatile syntax you can provide a custom template for the generated text.
!!!Examples:
[[ShowUpdatesDocs]]
!!!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
!!!Syntax:
{{{<<showUpdates>>}}}
additional optional params:
{{{<showUpdates excludeTag:TagToExclude onlyTag:TagToList maxEntries:10 write:CustomWriteParameter >>}}}
excludeTag: ~TagToExclude
onlyTag: ~TagToList
maxEntries: max number of entries displayed when there are no updates. (default is 10, which can be changed in the config.macros.showUpdates.settings part of the code)
write: if a write parameter is not provided, an un-numbered list of the updates is generated. Alternatively, you can specify a custom 'template' for the text generated. The syntax for the write parameter is identical to that of the forEachTiddler macro. Additonal documentation on this syntax will be provided soon.
Some of the variables available in the write parameter are 'index', 'count' and 'lastVisit' where lastVisit is the date of the last visit in the format YYYYMMDDHHMM. Also areUpdates is a boolean that is true if there are new updates since the users last visit.
!!!To Do:
*refactor code to facilitate translations
*a streamlined version without the custom write parameter
!!!Code
***/
//{{{
window.lewcidLastVisit = '';
window.old_lewcid_whatsnew_restart = window.restart;
window.restart = function()
{
if(config.options.txtLastVisit)
lewcidLastVisit= config.options.txtLastVisit;
config.options.txtLastVisit = (new Date()).convertToYYYYMMDDHHMM();
saveOptionCookie('txtLastVisit');
window.old_lewcid_whatsnew_restart();
}
TiddlyWiki.prototype.lewcidGetTiddlers = function(field,excludeTag,includeTag,updatesOnly)
{
var results = [];
this.forEachTiddler(function(title,tiddler)
{
if(excludeTag == undefined || !tiddler.isTagged(excludeTag))
if(includeTag == undefined || tiddler.isTagged(includeTag))
if ( updatesOnly == false || tiddler.modified.convertToYYYYMMDDHHMM()>lewcidLastVisit)
results.push(tiddler);
});
if(field)
results.sort(function (a,b) {if(a[field] == b[field]) return(0); else return (a[field] < b[field]) ? -1 : +1; });
return results;
}
config.macros.showUpdates={};
config.macros.showUpdates.settings =
{
maxEntries: 10 //max items to show, if there are no updates since last visit
}
config.macros.showUpdates.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
var args = paramString.parseParams("list",null,true);
var write = getParam(args, "write", undefined);
var onlyTag = getParam(args, "onlyTag", undefined);
var excludeTag = getParam(args, "excludeTag", undefined);
var sortBy = "modified";
var maxEntries = getParam(args,"maxEntries",this.settings.maxEntries);
if (lewcidLastVisit)
{var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,true);
var areUpdates = tiddlers.length>0? true:false;}
if (!lewcidLastVisit)
{var countLine = "!!Recent Updates:";
var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,false);
var areUpdates = false;}
else if (tiddlers.length == 0)
{var countLine = "!!@@color:red;No new updates@@ since your last visit. @@color:#999;font-size:70%;" + (Date.convertFromYYYYMMDDHHMM(lewcidLastVisit)).formatString(" (DD/MM/YY)") + "@@\n!!Recent Updates:";
var tiddlers = store.lewcidGetTiddlers(sortBy,excludeTag,onlyTag,false);}
else
{var countLine ="!!@@color:red;"+ tiddlers.length + "@@ new " + (tiddlers.length==1?"update":"updates") + " since your last visit: @@color:#999;font-size:70%;" + (Date.convertFromYYYYMMDDHHMM(lewcidLastVisit)).formatString(" (DD/MM/YY)") + "@@";}
tiddlers = tiddlers.reverse();
var lastVisit = lewcidLastVisit? lewcidLastVisit:undefined;
var count = areUpdates == true? tiddlers.length : maxEntries;
var sp = createTiddlyElement(place,"span","showUpdates");
if (write==undefined)
{
wikify(countLine,sp);
var list = createTiddlyElement(sp,"ul");
for (var i = 0; i < count; i++)
{
var tiddler = tiddlers[i];
createTiddlyLink(createTiddlyElement(list,"li"), tiddler.title, true);
}
}
else
{
var list = '';
for (var index = 0; index < count; index++) {
var tiddler = tiddlers[index];
list += eval(write); }
wikify(list, sp);
}
}
//}}}
<<tiddler SideBarCal>><<tiddler SideBarFavs>><<tiddler SideBarUnsaved>><<tiddler SideBarTabs>>
<<slider chkSideBarCalSlider "./partCal" "calendar">><script>
var b = place.lastChild.previousSibling;
var s = b.style;
s.marginLeft=".3em"; s.display="block"; s.padding=".2em";
b.innerHTML=(new Date()).formatString("MMM DD, YYYY");
</script>
<part partCal hidden>
{{indent{
<<calendar thismonth>><script>
place.lastChild.style.width="90%";
</script>
}}}
</part>
+++(favourites)[favourites]>...
<script>
treeTraverseNestedSliders = function(title,depth,sortBy,sortOrder)
{
var list = store.getTaggedTiddlers(title);
if (sortBy!="title")
list.sort(function(a,b) {
var x=zFunctions.fSort.getSortKey(a,sortBy);
var y=zFunctions.fSort.getSortKey(b,sortBy);
var z=(x<y?-1:(x==y?0:1))
return z;
});
if (sortOrder == "desc")
list.reverse();
var childOutput = "";
for (var i=0;i<list.length;i++)
if (list[i].title != title)
if (config.taggly.notHidden(list[i].title,this.config.inTiddler))
childOutput += treeTraverseNestedSliders(list[i].title,depth+1,sortBy,sortOrder);
if (depth == 0)
return childOutput;
else
return "[["+title+"]]+++["+config.taggly.getTaggingCount(title)+" ]>"+childOutput+"===\n\n";
};
return treeTraverseNestedSliders("fav",0,"orderingkey","asc");
</script>
===
<script>
var b=place.lastChild.button.style;
b.marginLeft=".3em";
b.marginBottom=".5em";
b.display="block";
b.padding=".2em";
var d=place.lastChild.style;
d.marginBottom="1em";
</script>
<<slider chkSideBarOptions SideBarOptions options '(shadow tiddler)'>><script>
var s=place.lastChild.previousSibling.style;
s.marginLeft=".3em"; s.display="block"; s.padding=".2em";
</script>
/%▐▀
Commented out unsavedChanges
▄▌%/
{{small{
/%@@display:block;line-height:2em;margin-left:.5em;<<unsavedChanges command "unsaved changes (%0)">>@@/%
%/+++(contents)[contents]...
<<tabs txtMainTab
Listbox 'TableOfContentsPlugin enhanced listbox' SideBarTabsListbox
Timeline Timeline TabTimeline
All 'All tiddlers' TabAll
Tags 'All tags' TabTags
More 'More lists' TabMore>>===
<script>
var s=place.lastChild.button.style;
s.marginLeft=".3em"; s.display="block"; s.padding=".2em";
</script>}}}
/%▐▀
Added «size:auto» macro parameter
▄▌%/
<<tableOfContents "label:select a tiddler" date:YYYY.0MM.0DD width:100% padding:0 margin:0 size:auto>><script>place.id="TOCListbox";place.lastChild.lastChild.style.color="#000";</script>
{{small{<script>
place.style.display=config.macros.unsavedChanges.changed.length?"block":"none";
</script>@@display:block;margin-left:.5em;line-height:150%;++++(sidebarunsaved)[unsaved changes]...
{{borderleft small{
{{borderbottom{
<<unsavedChanges list '<br>'>>/%
%/}}}/%
%/<script label="save to disk" key="S"> // adds forced refresh to 'save to disk' handling
saveChanges();
var anim=config.options.chkAnimate; // save animation setting
config.options.chkAnimate=false; // suspend animation
store.notify("SideBarTabs",true); // force refresh after saving
config.options.chkAnimate=anim; // restore animation setting
return false;
</script><script>
place.lastChild.innerHTML=config.macros.saveChanges.label;
place.lastChild.style.fontWeight="normal";
</script> | /%
%/<<upload http://nameanyone.tiddlyspot.com/store.cgi index.html . . nameanyone>>/%
%/}}}===/%
%/<script>
var t=" unsaved changes ("+config.macros.unsavedChanges.changed.length+")"
place.lastChild.button.innerHTML=t;
place.lastChild.button.setAttribute("closedtext",t);
place.lastChild.button.setAttribute("openedtext",t);
</script>/%
%/@@}}}
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.9.6|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Story.prototype.displayTiddler(), Story.prototype.displayTiddlers()|
|Options|##Configuration|
|Description|Show tiddlers one at a time with automatic permalink, or always open tiddlers at top/bottom of page.|
This plugin allows you to configure TiddlyWiki to navigate more like a traditional multipage web site with only one tiddler displayed at a time.
!!!!!Documentation
>see [[SinglePageModePluginInfo]]
!!!!!Configuration
<<<
<<option chkSinglePageMode>> Display one tiddler at a time
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
><<option chkSinglePageKeepFoldedTiddlers>> Don't close tiddlers that are folded
><<option chkSinglePageKeepEditedTiddlers>> Don't close tiddlers that are being edited
<<option chkTopOfPageMode>> Open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Open tiddlers at the bottom of the page
<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed)
Notes:
* The "display one tiddler at a time" option can also be //temporarily// set/reset by including a 'paramifier' in the document URL: {{{#SPM:true}}} or {{{#SPM:false}}}.
* If more than one display mode is selected, 'one at a time' display takes precedence over both 'top' and 'bottom' settings, and if 'one at a time' setting is not used, 'top of page' takes precedence over 'bottom of page'.
* When using Apple's Safari browser, automatically setting the permalink causes an error and is disabled.
<<<
!!!!!Revisions
<<<
2008.10.17 [2.9.6] changed chkSinglePageAutoScroll default to false
| Please see [[SinglePageModePluginInfo]] for previous revision details |
2005.08.15 [1.0.0] Initial Release. Support for BACK/FORWARD buttons adapted from code developed by Clint Checketts.
<<<
!!!!!Code
***/
//{{{
version.extensions.SinglePageModePlugin= {major: 2, minor: 9, revision: 6, date: new Date(2008,10,17)};
//}}}
//{{{
config.paramifiers.SPM = { onstart: function(v) {
config.options.chkSinglePageMode=eval(v);
if (config.options.chkSinglePageMode && config.options.chkSinglePagePermalink && !config.browser.isSafari) {
config.lastURL = window.location.hash;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
} };
//}}}
//{{{
if (config.options.chkSinglePageMode==undefined)
config.options.chkSinglePageMode=false;
if (config.options.chkSinglePagePermalink==undefined)
config.options.chkSinglePagePermalink=true;
if (config.options.chkSinglePageKeepFoldedTiddlers==undefined)
config.options.chkSinglePageKeepFoldedTiddlers=false;
if (config.options.chkSinglePageKeepEditedTiddlers==undefined)
config.options.chkSinglePageKeepEditedTiddlers=false;
if (config.options.chkTopOfPageMode==undefined)
config.options.chkTopOfPageMode=false;
if (config.options.chkBottomOfPageMode==undefined)
config.options.chkBottomOfPageMode=false;
if (config.options.chkSinglePageAutoScroll==undefined)
config.options.chkSinglePageAutoScroll=false;
//}}}
//{{{
config.SPMTimer = 0;
config.lastURL = window.location.hash;
function checkLastURL()
{
if (!config.options.chkSinglePageMode)
{ window.clearInterval(config.SPMTimer); config.SPMTimer=0; return; }
if (config.lastURL == window.location.hash) return; // no change in hash
var tids=decodeURIComponent(window.location.hash.substr(1)).readBracketedList();
if (tids.length==1) // permalink (single tiddler in URL)
story.displayTiddler(null,tids[0]);
else { // restore permaview or default view
config.lastURL = window.location.hash;
if (!tids.length) tids=store.getTiddlerText("DefaultTiddlers").readBracketedList();
story.closeAllTiddlers();
story.displayTiddlers(null,tids);
}
}
if (Story.prototype.SPM_coreDisplayTiddler==undefined)
Story.prototype.SPM_coreDisplayTiddler=Story.prototype.displayTiddler;
Story.prototype.displayTiddler = function(srcElement,tiddler,template,animate,slowly)
{
var title=(tiddler instanceof Tiddler)?tiddler.title:tiddler;
var tiddlerElem=document.getElementById(story.idPrefix+title); // ==null unless tiddler is already displayed
var opt=config.options;
var single=opt.chkSinglePageMode && !startingUp;
var top=opt.chkTopOfPageMode && !startingUp;
var bottom=opt.chkBottomOfPageMode && !startingUp;
if (single) {
story.forEachTiddler(function(tid,elem) {
// skip current tiddler and, optionally, tiddlers that are folded.
if ( tid==title
|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
return;
// if a tiddler is being edited, ask before closing
if (elem.getAttribute("dirty")=="true") {
if (opt.chkSinglePageKeepEditedTiddlers) return;
// if tiddler to be displayed is already shown, then leave active tiddler editor as is
// (occurs when switching between view and edit modes)
if (tiddlerElem) return;
// otherwise, ask for permission
var msg="'"+tid+"' is currently being edited.\n\n";
msg+="Press OK to save and close this tiddler\nor press Cancel to leave it opened";
if (!confirm(msg)) return; else story.saveTiddler(tid);
}
story.closeTiddler(tid);
});
}
else if (top)
arguments[0]=null;
else if (bottom)
arguments[0]="bottom";
if (single && opt.chkSinglePagePermalink && !config.browser.isSafari) {
window.location.hash = encodeURIComponent(String.encodeTiddlyLink(title));
config.lastURL = window.location.hash;
document.title = wikifyPlain("SiteTitle") + " - " + title;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
var isTopTiddler=(tiddlerElem.previousSibling==null);
if (!isTopTiddler && (single || top))
tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
else if (bottom)
tiddlerElem.parentNode.insertBefore(tiddlerElem,null);
else this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
} else
this.SPM_coreDisplayTiddler.apply(this,arguments); // let CORE render tiddler
var tiddlerElem=document.getElementById(story.idPrefix+title);
if (tiddlerElem&&opt.chkSinglePageAutoScroll) {
// scroll to top of page or top of tiddler
var isTopTiddler=(tiddlerElem.previousSibling==null);
var yPos=isTopTiddler?0:ensureVisible(tiddlerElem);
// if animating, defer scroll until after animation completes
var delay=opt.chkAnimate?config.animDuration+10:0;
setTimeout("window.scrollTo(0,"+yPos+")",delay);
}
}
if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
// suspend single/top/bottom modes when showing multiple tiddlers
var opt=config.options;
var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
this.SPM_coreDisplayTiddlers.apply(this,arguments);
opt.chkBottomOfPageMode=saveBPM;
opt.chkTopOfPageMode=saveTPM;
opt.chkSinglePageMode=saveSPM;
}
//}}}
@@margin:0 1em;@@
goto<<gotoTiddler>> |<script>config.macros.search.label=undefined;</script>
search <<search>> |
<<snapshot print label:snapshot id:story>> |
save: <<saveAs "label:empty" "prompt:save a copy without any content tiddlers to wiki.empty.sandbox.html" quiet open
includeNew or systemConfig or systemServer or BackstagePackage or CSS or html or CoreTiddlers>>
or <<saveAs "label:tspot" "prompt:save a copy for tiddlyspot to wiki.empty.tspot.html" quiet open
includeNew or systemConfig or systemServer or BackstagePackage or CSS or html or CoreTiddlers
or tspot>>
@@margin:0 4em;@@
user: <script label="X">
/*
"X" here and elsewhere means that the label is set programmatically.
Note that if SiteMenu is displayed in Story as well as on top of the window,
only the label that was actually clicked will be refreshed.
*/
var who=prompt("Set your username:",config.options.txtUserName);
if (!who||!who.trim().length) return; // cancelled by user
// set new username
config.options.txtUserName=who;
saveOptionCookie("txtUserName");
place.innerHTML=config.options.txtUserName;
if (place.innerHTML == 'YourName') {
place.style.fontWeight='bold';
place.style.color='red';
} else {
place.style.fontWeight='';
place.style.color='';
}
return false;
</script><script>
place.lastChild.innerHTML=config.options.txtUserName;
if (place.lastChild.innerHTML == 'YourName') {
place.lastChild.style.fontWeight='bold';
place.lastChild.style.color='red';
}
</script>
<<tiddler TiddlyWiki keyboard shortcuts>>
<<tiddler zFunctions>>
/% turn autoscroll on with delay, so that StorySaverPlugin does not cause the page to scroll to the bottom at startup %/
<script>
setTimeout("config.options.chkSinglePageAutoScroll=true",1);
</script>
/***
|Name|SnapshotPlugin|
|Source|http://www.TiddlyTools.com/#SnapshotPlugin|
|Documentation|http://www.TiddlyTools.com/#SnapshotPluginInfo|
|Version|1.1.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|save or print HTML+CSS image of rendered document content|
|Status|ALPHA - DO NOT DISTRIBUTE|
This plugin provides a macro as well as tiddler toolbar commands to create a file or browser window containing the //rendered// CSS-and-HTML that is currently being displayed for selected elements of the current document.
!!!!!Documentation
>see [[SnapshotPluginInfo]]
!!!!!Configuration
<<<
<<option chkSnapshotHTMLOnly>> output HTML only (omit CSS)
<<<
!!!!!Revisions
<<<
2008.05.16 [1.1.1] added try..catch around addEvent/removeEvent calls to avoid error in Opera
2008.04.28 [1.1.0] removed 'viewerHTML' from 'ask' droplist and replaced with toggle for "output HTML only". Removed 'noCSS' parameter and replaced with config.options.chkSnapshotHTMLOnly global option. Added "select a tiddler..." to 'ask' droplist
2008.04.24 [1.0.1] in saveSnap(), convert output from Unicode to UTF before passing to saveFile(). Fixes "unknown name" error in IE's file.Write() function. Added viewerHTML to 'ask' droplist.
2008.04.21 [1.0.0] initial release - derived from [[NewDocumentPlugin]] with many improvements, including: "ask for ID" using droplist of available DOM elements, use "<base href=...>" for correctly resolving image references, wrap 'viewer only' output in class="tiddler viewer" for proper application of inherited CSS styles, snapshotSave and snapshotPrint tiddler toolbar command definitions, and more...
<<<
!!!!!Code
***/
//{{{
version.extensions.SnapshotPlugin= {major: 1, minor: 1, revision: 1, date: new Date(2008,5,16)};
if (config.options.chkSnapshotHTMLOnly===undefined) config.options.chkSnapshotHTMLOnly=false;
config.macros.snapshot = {
snapLabel: "save a snapshot",
printLabel: "print a snapshot",
snapPrompt: "save an HTML image of rendered content",
printPrompt: "print an HTML image of rendered content",
hereID: "here",
viewerID: "viewer",
storyID: "story",
allID: "all",
askID: "ask",
askTiddlerID: "askTiddler",
askDOMID: "askDOM",
askMsg: "select an element...",
hereItem: "tiddler: '%0'",
viewerItem: "tiddler: '%0' (content only)",
storyItem: "story column",
allItem: "entire document",
tiddlerItem: "select a tiddler...",
IDItem: "select a DOM element by ID...",
HTMLItem: "[%0] output HTML only (omit CSS)",
fileMsg: "select or enter a target path/filename",
defaultFilename: "snapshot.html",
okmsg: "snapshot written to %0",
failmsg: "An error occurred while creating %0",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var printing=params[0]&¶ms[0]=="print"; if (printing) params.shift();
params = paramString.parseParams("anon",null,true,false,false);
var id=getParam(params,"id","here");
var label=getParam(params,"label",printing?this.printLabel:this.snapLabel);
var prompt=getParam(params,"prompt",printing?this.printPrompt:this.snapPrompt);
var btn=createTiddlyButton(place,label,prompt, function(ev){
this.setAttribute("snapID",this.getAttribute("startID"));
config.macros.snapshot.go(this,ev)
});
btn.setAttribute("startID",id);
btn.setAttribute("snapID",id);
btn.setAttribute("printing",printing?"true":"false");
btn.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
},
go: function(here,ev) {
var cms=config.macros.snapshot; // abbreviation
var id=here.getAttribute("snapID");
var printing=here.getAttribute("printing")=="true";
var HTMLOnly=here.getAttribute("HTMLOnly")=="true";
if (id==cms.askID||id==cms.askTiddlerID||id==cms.askDOMID) {
cms.askForID(here,ev);
} else {
// get element
if (id==cms.storyID) id="tiddlerDisplay";
if (id==cms.allID) id="contentWrapper";
var snapElem=document.getElementById(id);
if (id==cms.hereID || id==cms.viewerID)
var snapElem=story.findContainingTiddler(here);
if (snapElem && hasClass(snapElem,"tiddler") && (id==cms.viewerID || HTMLOnly)) {
// find viewer class element within tiddler element
var nodes=snapElem.getElementsByTagName("*");
for (var i=0; i<nodes.length; i++)
if (hasClass(nodes[i],"viewer")) { snapElem=nodes[i]; break; }
}
if (!snapElem) // not in a tiddler or no viewer element or unknown ID
{ e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return(false); }
// write or print snapshot
var out=cms.getsnap(snapElem,id,printing,HTMLOnly);
if (printing) cms.printsnap(out); else cms.savesnap(out);
}
return false;
},
askForID: function(here,ev) {
var ev = ev ? ev : window.event;
var cms=config.macros.snapshot; // abbreviation
var id=here.getAttribute("snapID");
var indent='\xa0\xa0\xa0\xa0';
var p=Popup.create(here); if (!p) return false; p.className+=' sticky smallform';
var s=createTiddlyElement(p,'select'); s.button=here;
if (id==cms.askID) {
s.options[s.length]=new Option(cms.askMsg,cms.askID);
var tid=story.findContainingTiddler(here);
if(tid) {
var title=tid.getAttribute("tiddler");
if (here.getAttribute("HTMLOnly")!="true")
s.options[s.length]=new Option(indent+cms.hereItem.format([title]),cms.hereID);
s.options[s.length]=new Option(indent+cms.viewerItem.format([title]),cms.viewerID);
}
s.options[s.length]=new Option(indent+cms.tiddlerItem,cms.askTiddlerID);
s.options[s.length]=new Option(indent+cms.IDItem,cms.askDOMID);
s.options[s.length]=new Option(indent+cms.storyItem,"tiddlerDisplay");
s.options[s.length]=new Option(indent+cms.allItem,"contentWrapper");
}
if (id==cms.askDOMID) {
s.options[s.length]=new Option(cms.IDItem,cms.askDOMID);
var elems=document.getElementsByTagName("*");
var ids=[];
for (var i=0;i<elems.length;i++)
if (elems[i].id.length && elems[i].className!="animationContainer")
ids.push(elems[i].id);
ids.sort();
for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i],ids[i]);
}
if (id==cms.askTiddlerID) {
s.options[s.length]=new Option(cms.tiddlerItem,cms.askTiddlerID);
var elems=document.getElementsByTagName("div");
var ids=[];
for (var i=0;i<elems.length;i++) { var id=elems[i].id;
if (id.length && id.substr(0,story.idPrefix.length)==story.idPrefix && id!="tiddlerDisplay")
ids.push(id);
}
ids.sort();
for (var i=0;i<ids.length;i++) s.options[s.length]=new Option(indent+ids[i].substr(story.idPrefix.length),ids[i]);
}
s.options[s.length]=new Option(cms.HTMLItem.format([here.getAttribute("HTMLOnly")=="true"?"\u221a":"_"]),cms.HTMLItem);
s.onchange=function(ev){
var ev = ev ? ev : window.event;
var cms=config.macros.snapshot; // abbreviation
var here=this.button;
if (this.value==cms.HTMLItem) {
config.options.chkSnapshotHTMLOnly=!config.options.chkSnapshotHTMLOnly;
here.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
config.macros.option.propagateOption("chkSnapshotHTMLOnly","checked",
config.options.chkSnapshotHTMLOnly,"input");
} else
here.setAttribute("snapID",this.value);
config.macros.snapshot.go(here,ev);
return false;
};
Popup.show(p,false);
ev.cancelBubble=true;
if(ev.stopPropagation)ev.stopPropagation();
return false;
},
getpath: function() {
// get current path
var path=getLocalPath(window.location.href);
var slashpos=path.lastIndexOf("/");
if (slashpos==-1) slashpos=path.lastIndexOf("\\");
if (slashpos!=-1) path=path.substr(0,slashpos+1); // trim filename
return path;
},
getsnap: function(snapElem,id,printing,HTMLOnly) {
var cms=config.macros.snapshot; // abbreviation
var out="";
out+="<html><head>\n";
if (printing)
out+='<base href="file:///'+cms.getpath().replace(/\\/g,'/')+'"></base>\n';
if (!HTMLOnly) {
var styles=document.getElementsByTagName("style");
for(var i=0; i < styles.length; i++) {
out+="<style>\n";
out+="/* stylesheet="+styles[i].getAttribute("id")+" */\n";
out+=styles[i].innerHTML+"\n\n";
out+="</style>\n";
}
}
out+="</head><body>\n\n<div"+(id==cms.viewerID?" class='tiddler viewer'>":">");
out+=snapElem.innerHTML;
out+="</div>\n\n</body>\n";
out+="</html>";
return out;
},
printsnap: function(out) {
var win=window.open("","_blank","");
win.document.open();
win.document.writeln(out);
win.document.close();
win.focus(); // bring to front
win.print(); // trigger print dialog
},
savesnap: function(out) {
var cms=config.macros.snapshot; // abbreviation
// make sure we are local
if (window.location.protocol!="file:")
{ alert(config.messages.notFileUrlError); return; }
var target=cms.askForFilename(cms.fileMsg,cms.getpath(),cms.defaultFilename);
if (!target) return; // cancelled by user
// if specified file does not include a path, assemble fully qualified path and filename
var slashpos=target.lastIndexOf("/");
if (slashpos==-1) slashpos=target.lastIndexOf("\\");
if (slashpos==-1) target=target+cms.defaultFilename;
var link="file:///"+target.replace(/\\/g,'/'); // link for message text
var ok=saveFile(target,convertUnicodeToUTF8(out));
var msg=ok?cms.okmsg.format([target]):cms.failmsg.format([target]);
clearMessage(); displayMessage(msg,link);
},
askForFilename: function(msg,path,file) {
if(window.Components) { // moz
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, nsIFilePicker.modeSave);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='html';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
}
catch(e) { alert('error during local file access: '+e.toString()) }
}
else { // IE
try { // XP/Vista only
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
s.FilterIndex=3; // default to HTML files;
s.InitialDir=path;
s.FileName=file;
if (s.showOpen()) var result=s.FileName;
}
catch(e) { var result=prompt(msg,path+file); } // fallback for non-XP IE
}
return result;
}
};
//}}}
// // TOOLBAR DEFINITIONS
//{{{
config.commands.snapshotSave = {
text: "snap",
tooltip: config.macros.snapshot.snapPrompt,
handler: function(ev,src,title) {
src.setAttribute("snapID","ask");
src.setAttribute("printing","false");
src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
config.macros.snapshot.go(src,ev);
return false;
}
};
config.commands.snapshotPrint = {
text: "print",
tooltip: config.macros.snapshot.printPrompt,
handler: function(ev,src,title) {
src.setAttribute("snapID","ask");
src.setAttribute("printing","true");
src.setAttribute("HTMLOnly",config.options.chkSnapshotHTMLOnly?"true":"false");
config.macros.snapshot.go(src,ev);
return false;
}
};
//}}}
// // COPIED FROM [[StickyPopupPlugin]] TO ELIMINATE PLUGIN DEPENDENCY
//{{{
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
// if click is in a sticky popup, ignore it so popup will remain visible
var e = ev ? ev : window.event; var target = resolveTarget(e);
var p=target; while (p) {
if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
else p=p.parentNode;
}
if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
Popup.onDocumentClick(ev);
return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/***
|Name|StickyPopupPlugin|
|Source|http://www.TiddlyTools.com/#StickyPopupPlugin|
|Version|1.0.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides|Popup.onDocumentClick|
|Options|##Configuration|
|Description|allow mouse interactions inside popups without automatically closing them|
Usually, when a TW popup is displayed, it is automatically closed whenever a click occurs //anywhere// in the document, either //inside// or //outside// the popup itself. This plugin makes popups persistent (a.k.a, "sticky"), allowing you to perform multiple mouse interactions on content //inside// the popup (e.g., entering form fields, opening links, selecting text, etc.), remaining visible until you click //outside// the popup or perform an action that opens another popup (only one popup can be displayed at any given time).
!!!!!Configuration
<<<
You can cause popups to behave in a persistent ("sticky") manner simply by selecting the option checkbox below. The selected popup display behavior will be applied to ALL popups in the document automatically.
><<option chkStickyPopups>> make all popups "sticky"
>{{{usage: <<option chkStickyPopups>>}}}
<<<
!!!!!Usage
<<<
If you are developing your own plugins or inline scripts that create popups programmatically using the core function:
{{{
Popup.create(this)
}}}
you can provide additional parameters that specify the desired CSS classname(s) to assign to the popup DOM element. The default class when none is specified is simply "popup". To create a //sticky// popup, simply enter a custom class combination like this:
{{{
Popup.create(this,null,"sticky popup")
}}}
<<<
!!!!!Revisions
<<<
2008.05.16 [1.0.1] added try..catch around addEvent/removeEvent calls to avoid error in Opera
2007.11.25 [1.0.0] initial release - moved from [[CoreTweaks]]
<<<
!!!!!Code
***/
//{{{
version.extensions.StickyPopups= {major: 1, minor: 0, revision: 1, date: new Date(2008,5,16)};
if (config.options.chkStickyPopups==undefined) config.options.chkStickyPopups=false;
Popup.stickyPopup_onDocumentClick = function(ev)
{
// if click is in a sticky popup, ignore it so popup will remain visible
var e = ev ? ev : window.event; var target = resolveTarget(e);
var p=target; while (p) {
if (hasClass(p,"popup") && (hasClass(p,"sticky")||config.options.chkStickyPopups)) break;
else p=p.parentNode;
}
if (!p) // not in sticky popup (or sticky popups disabled)... use normal click handling
Popup.onDocumentClick(ev);
return true;
};
try{removeEvent(document,"click",Popup.onDocumentClick);}catch(e){};
try{addEvent(document,"click",Popup.stickyPopup_onDocumentClick);}catch(e){};
//}}}
/%
StoryMenu is a menu at the bottom of the Story (after the last open tiddler).
Currently empty but here's an example:
{{center{{{fine{<<unsavedChanges>>}}}}}}
%/
/***
|Name|StorySaverPlugin|
|Source|http://www.TiddlyTools.com/#StorySaverPlugin|
|Documentation|http://www.TiddlyTools.com/#StorySaverPluginInfo|
|Version|1.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|MarkupPostBody|
|Overrides|confirmExit(), getParameters()|
|Description|save/restore current tiddler view between browser sessions|
This plugin automatically saves a list of the currently viewed tiddlers (the "story") in a local cookie, {{{txtSavedStory}}} and then opens those tiddlers when the document is subsequently reloaded... the tiddlers you were viewing in the last browser session are automatically redisplayed in the next session, allowing you to quickly resume working with the document from the same place you left off!!
In addition to automatic cookie-based story tracking, the plugin also provides {{{<<saveStory>>}}} and {{{<<openStory>>}}} macros that allow you to quickly save the current story definition to a tiddler, and then re-display saved stories using simple, one-click command links or droplists.
!!!!!Documentation
>see [[StorySaverPluginInfo]]
!!!!!Revisions
<<<
2008.09.07 [1.4.3] added removeOptionCookie() function for compatibility with [[CookieManagerPlugin]]
2008.07.11 [1.4.2] in confirmExit(), corrected bracketing for titles containing spaces
2008.03.10 [*.*.*] plugin size reduction: documentation moved to [[StorySaverPluginInfo]]
|please see [[StorySaverPluginInfo]] for additional revision details|
2007.10.05 [1.0.0] initial release. Moved [[SetDefaultTiddlers]] inline script and rewrote as a {{{<<saveStory>>}}} macro.
<<<
!!!!!Code
***/
//{{{
version.extensions.StorySaver= {major: 1, minor: 4, revision: 3, date: new Date(2008,9,7)};
//}}}
// // ''save or clear story cookie on exit:''
//{{{
// if removeOptionCookie() function is not defined by TW core, define it here.
if (window.removeOptionCookie===undefined) {
window.removeOptionCookie=function(cookie) {
var ex=new Date(); ex.setTime(ex.getTime()-1000); // immediately expire cookie
document.cookie = cookie+"=novalue; path=/; expires="+ex.toGMTString();
}
}
if (config.options.chkSaveStory==undefined) config.options.chkSaveStory=false;
if (window.coreTweaks_confirmExit==undefined) {
window.coreTweaks_confirmExit=window.confirmExit;
window.confirmExit=function() {
if (config.options.chkSaveStory) { // save cookie
var links=[];
story.forEachTiddler(function(title,element){links.push('[['+title+']]');});
config.options.txtSavedStory=links.join(" ");
saveOptionCookie("txtSavedStory");
} else removeOptionCookie("txtSavedStory");
return window.coreTweaks_confirmExit.apply(this,arguments);
}
}
//}}}
/***
''apply saved story on startup:'' //important note: the following code is actually located in [[MarkupPostBody]]. This is because it needs to supercede the core's getParameters() function, which is called BEFORE plugins are loaded, preventing the normal plugin-based hijack method from working, while code loaded into [[MarkupPostBody]] will be processed as soon as the document is read, even before the TW main() function is invoked.//
<<tiddler MarkupPostBody>>
***/
// // MACRO definitions
//{{{
config.macros.saveStory = {
label: "set default tiddlers",
defaultTiddler: "DefaultTiddlers",
prompt: "store a list of currently displayed tiddlers in another tiddler",
askMsg: "Enter the name of a tiddler in which to save the current story:",
tag: "story",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var tid=params[0]?params[0]:"DefaultTiddlers";
var label=params[1]?params[1]:this.label;
var tip=params[2]?params[2]:this.prompt;
var btn=createTiddlyButton(place,label,tip,this.setTiddler,"button");
btn.setAttribute("tid",tid);
},
setTiddler: function() {
// get list of current open tiddlers
var tids=[];
story.forEachTiddler(function(title,element){tids.push("[["+title+"]]")}); // always put titles in brackets
// get target tiddler
var tid=this.getAttribute("tid");
if (!tid || tid=="ask") {
tid=prompt(config.macros.saveStory.askMsg,config.macros.saveStory.defaultTiddler);
if (!tid || !tid.length) return; // cancelled by user
}
if(store.tiddlerExists(tid) && !confirm(config.messages.overwriteWarning.format([tid]))) return;
tids=tids.join("\n"); // separate tiddler links by newlines for easier reading
var t=store.getTiddler(tid); var tags=t?t.tags:[]; tags.push(config.macros.saveStory.tag);
store.saveTiddler(tid,tid,tids,config.options.txtUserName,new Date(),tags,t?t.fields:null);
story.displayTiddler(null,tid); story.refreshTiddler(tid,null,true);
displayMessage(tid+" has been "+(t?"updated":"created"));
}
}
//}}}
//{{{
if (config.options.chkStoryFold==undefined) config.options.chkStoryFold=true;
if (config.options.chkStoryClose==undefined) config.options.chkStoryClose=true;
config.macros.openStory = {
label: "open story: %0",
prompt: "open the set of tiddlers listed in: '%0'",
popuplabel: "stories",
popupprompt: "view a set of tiddlers",
tag: "story",
selectprompt: "select a story...",
optionsprompt: "viewing options...",
foldcmd: "[%0] fold story",
foldprompt: "fold story tiddlers when opening a story",
closecmd: "[%0] close others",
closeprompt: "close other tiddlers when opening a story",
addcmd: "add a story...",
addprompt: "create a new story",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
if (params[0].toLowerCase()=="list") return this.createList(place,params);
else if (params[0].toLowerCase()=="popup") return this.createPopup(place,params);
else this.createButton(place,params);
},
showStory: function(tid) {
var tids=[];
var tagged=store.getTaggedTiddlers(tid,"title");
if (tagged.length) // if tiddler IS a tag, use tagged tiddlers as story
for (var t=0; t<tagged.length; t++) tids.push(tagged[t].title);
else { // get tiddler list from content
var t=store.getTiddler(tid);
if (t) { if (!t.linksUpdated) t.changed(); tids=t.links; }
}
// see [[CollapseTiddlersPlugin]] for more info, re: folding tiddlers
var template=null;
if (config.options.chkStoryFold) template="CollapsedTemplate";
if (!store.tiddlerExists("CollapsedTemplate")) template=null;
if (config.options.chkStoryClose) story.closeAllTiddlers();
story.displayTiddlers(null,tids,template);
},
createButton: function(place,params) {
var tid=params[0]?params[0]:"";
var label=params[1]?params[1]:this.label; label=label.format([tid]);
var tip=params[2]?params[2]:this.prompt; tip=tip.format([tid]);
var fn=function(){config.macros.openStory.showStory(this.getAttribute("tid"))};
var btn=createTiddlyButton(place,label,tip,fn,"button");
btn.setAttribute("tid",tid);
},
createPopup: function(place,params) {
var label=params[1]?params[1]:this.popuplabel;
var tip=params[2]?params[2]:this.popupprompt;
var btn=createTiddlyButton(place,label,tip,this.showPopup,"button");
},
showPopup: function(ev) { var e=ev||window.event;
var indent="\xa0\xa0";
var p=Popup.create(this); if (!p) return false;
createTiddlyText(createTiddlyElement(p,"li"),config.macros.openStory.selectprompt);
var stories=store.getTaggedTiddlers("story","title");
for (var s=0; s<stories.length; s++) {
var label=indent+stories[s].title;
var tip=config.macros.openStory.prompt.format([stories[s].title]);
var fn=function(){config.macros.openStory.showStory(this.getAttribute("tid"))};
var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
btn.setAttribute("tid",stories[s].title);
}
createTiddlyText(createTiddlyElement(p,"li"),config.macros.openStory.optionsprompt);
if (store.tiddlerExists("CollapsedTemplate")) {
var label=indent+config.macros.openStory.foldcmd.format([config.options.chkStoryFold?"x":"\xa0\xa0"]);
var tip=config.macros.openStory.foldprompt;
var fn=function(){config.options.chkStoryFold=!config.options.chkStoryFold;saveOptionCookie('chkStoryFold')};
var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
}
var label=indent+config.macros.openStory.closecmd.format([config.options.chkStoryClose?"x":"\xa0\xa0"]);
var tip=indent+config.macros.openStory.closeprompt;
var fn=function(){config.options.chkStoryClose=!config.options.chkStoryClose;saveOptionCookie('chkStoryClose')};
var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
if (!readOnly) {
var label=config.macros.openStory.addcmd;
var tip=config.macros.openStory.addprompt;
var fn=config.macros.saveStory.setTiddler;
createTiddlyElement(createTiddlyElement(p,"li"),"hr");
var btn=createTiddlyButton(createTiddlyElement(p,"li"),label,tip,fn,"button");
}
Popup.show(p,false);
e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();
return false;
},
createList: function(place,params) {
var s=createTiddlyElement(place,"select",null,"storyListbox");
s.size=1;
s.onchange=function() {
if (this.value=="_fold") {
config.options.chkStoryFold=!config.options.chkStoryFold; saveOptionCookie('chkStoryFold');
config.macros.openStory.refreshList();
} else if (this.value=="_close") {
config.options.chkStoryClose=!config.options.chkStoryClose; saveOptionCookie('chkStoryClose');
config.macros.openStory.refreshList();
} else if (this.value=="_add")
config.macros.saveStory.setTiddler.apply(this,arguments);
else config.macros.openStory.showStory(this.value);
}
setStylesheet(".storyListbox { width:100%; }", "StorySaverStyles");
store.addNotification(null,this.refreshList); this.refreshList();
return;
},
refreshList: function() {
var indent="\xa0\xa0\xa0\xa0";
var lists=document.getElementsByTagName("select");
for (var i=0; i<lists.length; i++) { if (lists[i].className!="storyListbox") continue;
var here=lists[i];
while (here.length) here.options[0]=null; // remove current list items
here.options[here.length]=new Option(config.macros.openStory.selectprompt,"",true,true);
var stories=store.getTaggedTiddlers("story","title");
for (var s=0; s<stories.length; s++)
here.options[here.length]=new Option(indent+stories[s].title,stories[s].title,false,false);
if (!readOnly)
here.options[here.length]=new Option(config.macros.openStory.addcmd,"_add",false,false);
here.options[here.length]=new Option(config.macros.openStory.optionsprompt,"",false,false);
if (store.tiddlerExists("CollapsedTemplate")) {
var msg=config.macros.openStory.foldcmd.format([config.options.chkStoryFold?"x":"\xa0\xa0"]);
here.options[here.length]=new Option(indent+msg,"_fold",false,false);
}
var msg=config.macros.openStory.closecmd.format([config.options.chkStoryClose?"x":"\xa0\xa0"]);
here.options[here.length]=new Option(indent+msg,"_close",false,false);
}
}
}
//}}}
/* Tiddler names must be enclosed in double-square brackets, otherwise their CSS does not get added to the StyleSheet. */
[[StyleSheetPlugins]]
[[StyleSheetShortcuts]]
[[zStyleSheet]]
/***
|Name|StyleSheetPlugins|
|Source|http://www.TiddlyTools.com/#StyleSheetPlugins|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|CSS|
|Requires||
|Overrides||
|Description|definitions for plugin-specific ID's and classes|
The following CSS declarations modify default style classes defined by various plugins and scripts, and/or used in customized Page/View/Edit templates
These 'style tweaks' can be easily included in other stylesheet tiddler so they can share a baseline look-and-feel that can then be customized to create a wide variety of 'flavors'.
/***
!PageTemplate - siteMenu
***/
/*{{{*/
.siteMenu
{ background:transparent; padding:.5em; padding-top:0; margin:0; }
.siteMenu a, .siteMenu .button, .siteMenu .tiddlyLinkExisting, .siteMenu .tiddlyLinkNonExisting
{ font-weight: normal; font-style: normal; }
/*** LEAVE THESE OUT FOR NOW
.siteMenu .button, .siteMenu a
{ border:1px solid transparent; background:transparent; margin:0px; padding:0px 1px; -moz-border-radius:.5em; }
.siteMenu .button:hover, .siteMenu a:hover
{ border:1px solid #69c; background:#006; color:#fff; }
***/
/*}}}*/
/***
!PageTemplate - storyMenu
***/
/*{{{*/
.storyMenu
{ display:block; margin:0em 1em .5em 1em; }
.storyMenu a, .storyMenu .button, .storyMenu .tiddlyLinkExisting, .storyMenu .tiddlyLinkNonExisting
{ font-weight: normal; font-style: normal; text-decoration:none; }
/*}}}*/
/***
!NestedSlidersPlugin
***/
/*{{{*/
.floatingPanel
{ z-index:700; padding:1em; margin:0em; border:1px solid; -moz-border-radius:1em; font-size:8pt; text-align:left; }
.floatingPanel hr
{ margin:2px 0 1px 0; padding:0; }
#sidebarOptions .sliderPanel
{ margin:0; padding:0; font-size:1em; background:transparent; }
#sidebarOptions .sliderPanel a
{ font-weight:normal; }
#sidebarOptions .sliderPanel blockquote
{ margin:0;padding:0;margin-left:1em; border-left:1px dotted; padding-left:1em }
.selected .floatingPanel .button,
.selected .floatingPanel a:link,
.selected .floatingPanel a:hover,
.selected .floatingPanel a:visited,
.floatingPanel .button,
.floatingPanel a:link,
.floatingPanel a:hover,
.floatingPanel a:visited
{ color:[[ColorPalette::PrimaryDark]] !important; }
/*}}}*/
/***
!CheckboxPlugin
***/
/*{{{*/
input[type="Checkbox"]
{ margin-top:2px;margin-bottom:2px; }
/*}}}*/
/***
!BreadcrumbsPlugin
***/
/*{{{*/
/* smaller size for bread crumbs (see BreadcrumbsPlugin) */
#breadCrumbs
{ display:none; margin:0em 1em; padding-bottom:.5em; font-size:7pt; } /* display:block is set by plugin when crumbs are in use */
/*}}}*/
/***
!TableOfContentsPlugin
***/
/*{{{*/
#sidebarTabs .tabContents *[class="TOCList"] /* MOZ ONLY */
{ background-color: transparent; border-color:transparent !important; }
/*}}}*/
/***
!AttachFilePlugin
***/
/*{{{*/
#sidebar .attachPanel
{ right:115%; top:3em; text-align:left; }
/*}}}*/
/***
!ImportTiddlersPlugin
***/
/*{{{*/
#sidebar #importPanel
{ right:115%; top:6em; text-align:left; }
/*}}}*/
/***
!ExportTiddlersPlugin
***/
/*{{{*/
#sidebar #exportPanel
{ right:115%; top:9em; text-align:left; }
/*}}}*/
/***
!QuoteOfTheDayPlugin
***/
/*{{{*/
.QOTD
{ color:inherit !important; background:inherit !important; }
/*}}}*/
/***
!TableSorterPlugin
***/
/*{{{*/
.sortedCol
{ color:inherit !important; background:inherit !important; }
/*}}}*/
/***
|Name|StyleSheetShortcuts|
|Source|http://www.TiddlyTools.com/#StyleSheetShortcuts|
|Version||
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|CSS|
|Requires||
|Overrides||
|Description|'convenience' classes for common formatting, alignment, boxes, tables, etc.|
These 'style tweaks' can be easily included in other stylesheet tiddler so they can share a baseline look-and-feel that can then be customized to create a wide variety of 'flavors'.
***/
/*{{{*/
/* text alignments */
.left
{ display:block;text-align:left; }
.center
{ display:block;text-align:center; }
.center table
{ margin:auto !important; }
.right
{ display:block;text-align:right; }
.justify
{ display:block;text-align:justify; }
.indent
{ display:block;margin:0;padding:0;border:0;margin-left:2em; }
.floatleft
{ float:left; }
.floatright
{ float:right; }
.valignTop, .valignTop table, .valignTop tbody, .valignTop th, .valignTop tr, .valignTop td
{ vertical-align:top; }
.valignBottom, .valignBottom table, .valignBottom tbody, .valignBottom th, .valignBottom tr, .valignBottom td
{ vertical-align:bottom; }
.clear
{ clear:both; }
.wrap
{ white-space:normal; }
.nowrap
{ white-space:nowrap; }
.hidden
{ display:none; }
.show
{ display:inline !important; }
.span
{ display:span; }
.block
{ display:block; }
.relative
{ position:relative; }
.absolute
{ position:absolute; }
/* font sizes */
.big
{ font-size:14pt;line-height:120% }
.medium
{ font-size:12pt;line-height:120% }
.normal
{ font-size:9pt;line-height:120% }
.small
{ font-size:8pt;line-height:120% }
.fine
{ font-size:7pt;line-height:120% }
.tiny
{ font-size:6pt;line-height:120% }
.larger
{ font-size:120%; }
.smaller
{ font-size:80%; }
/* font styles */
.bold
{ font-weight:bold; }
.italic
{ font-style:italic; }
.underline
{ text-decoration:underline; }
/* plain list items (no bullets or indent) */
.nobullets li { list-style-type: none; margin-left:-2em; }
/* multi-column tiddler content (not supported in Internet Explorer) */
.twocolumns { display:block;
-moz-column-count:2; -moz-column-gap:1em; -moz-column-width:50%; /* FireFox */
-webkit-column-count:2; -webkit-column-gap:1em; -webkit-column-width:50%; /* Safari */
column-count:2; column-gap:1em; column-width:50%; /* Opera */
}
.threecolumns { display:block;
-moz-column-count:3; -moz-column-gap:1em; -moz-column-width:33%; /* FireFox */
-webkit-column-count:3; -webkit-column-gap:1em; -webkit-column-width:33%; /* Safari */
column-count:3; column-gap:1em; column-width:33%; /* Opera */
}
.fourcolumns { display:block;
-moz-column-count:4; -moz-column-gap:1em; -moz-column-width:25%; /* FireFox */
-webkit-column-count:4; -webkit-column-gap:1em; -webkit-column-width:25%; /* Safari */
column-count:4; column-gap:1em; column-width:25%; /* Opera */
}
/* show/hide browser-specific content for InternetExplorer vs. non-IE ("moz") browsers */
*[class="ieOnly"]
{ display:none; } /* hide in moz (uses CSS selector) */
* html .mozOnly, *:first-child+html .mozOnly
{ display: none; } /* hide in IE (uses IE6/IE7 CSS hacks) */
/* borderless tables */
.borderless, .borderless table, .borderless td, .borderless tr, .borderless th, .borderless tbody
{ border:0 !important; margin:0 !important; padding:0 !important; }
.widetable, .widetable table
{ width:100%; }
/* thumbnail images (fixed-sized scaled images) */
.thumbnail img { height:5em !important; }
/* stretchable images (auto-size to fit tiddler) */
.stretch img { width:95%; }
/* grouped content */
.outline
{ display:block; padding:1em; -moz-border-radius:1em;-webkit-border-radius:1em; border:1px solid; }
.menubox
{ display:block; padding:1em; -moz-border-radius:1em;-webkit-border-radius:1em; border:1px solid; background:#fff; color:#000; }
.menubox .button, .menubox .tiddlyLinkExisting, .menubox .tiddlyLinkNonExisting
{ color:#009 !important; }
.groupbox
{ display:block; padding:1em; -moz-border-radius:1em;-webkit-border-radius:1em; border:1px solid; background:#ffe; color:#000; }
.groupbox a, .groupbox .button, .groupbox .tiddlyLinkExisting, .groupbox .tiddlyLinkNonExisting
{ color:#009 !important; }
.groupbox code
{ color:#333 !important; }
.borderleft
{ margin:0;padding:0;border:0;margin-left:1em; border-left:1px dotted; padding-left:.5em; }
.borderright
{ margin:0;padding:0;border:0;margin-right:1em; border-right:1px dotted; padding-right:.5em; }
.borderbottom
{ margin:0;padding:1px 0;border:0;border-bottom:1px dotted; margin-bottom:1px; padding-bottom:1px; }
.bordertop
{ margin:0;padding:0;border:0;border-top:1px dotted; margin-top:1px; padding-top:1px; }
/* scrolled content */
.scrollbars { overflow:auto; }
.height10em { height:10em; }
.height15em { height:15em; }
.height20em { height:20em; }
.height25em { height:25em; }
.height30em { height:30em; }
.height35em { height:35em; }
.height40em { height:40em; }
/* compact form */
.smallform
{ white-space:nowrap; }
.smallform input, .smallform textarea, .smallform button, .smallform checkbox, .smallform radio, .smallform select
{ font-size:8pt; }
/* stretchable edit fields and textareas (auto-size to fit tiddler) */
.stretch input { width:99%; }
.stretch textarea { width:99%; }
/* compact input fields (limited to a few characters for entering percentages and other small values) */
.onechar input { width:1em; }
.twochar input { width:2em; }
.threechar input { width:3em; }
.fourchar input { width:4em; }
.fivechar input { width:5em; }
/* text colors */
.white { color:#fff !important }
.gray { color:#999 !important }
.black { color:#000 !important }
.red { color:#f66 !important }
.green { color:#0c0 !important }
.blue { color:#99f !important }
/* rollover highlighting */
.mouseover
{color:[[ColorPalette::TertiaryLight]] !important;}
.mouseover a
{color:[[ColorPalette::TertiaryLight]] !important;}
.selected .mouseover
{color:[[ColorPalette::Foreground]] !important;}
.selected .mouseover .button, .selected .mouseover a
{color:[[ColorPalette::PrimaryDark]] !important;}
/* rollover zoom text */
.zoomover
{ font-size:80% !important; }
.selected .zoomover
{ font-size:100% !important; }
/* [[ColorPalette]] text colors */
.Background { color:[[ColorPalette::Background]]; }
.Foreground { color:[[ColorPalette::Foreground]]; }
.PrimaryPale { color:[[ColorPalette::PrimaryPale]]; }
.PrimaryLight { color:[[ColorPalette::PrimaryLight]]; }
.PrimaryMid { color:[[ColorPalette::PrimaryMid]]; }
.PrimaryDark { color:[[ColorPalette::PrimaryDark]]; }
.SecondaryPale { color:[[ColorPalette::SecondaryPale]]; }
.SecondaryLight { color:[[ColorPalette::SecondaryLight]];}
.SecondaryMid { color:[[ColorPalette::SecondaryMid]]; }
.SecondaryDark { color:[[ColorPalette::SecondaryDark]]; }
.TertiaryPale { color:[[ColorPalette::TertiaryPale]]; }
.TertiaryLight { color:[[ColorPalette::TertiaryLight]]; }
.TertiaryMid { color:[[ColorPalette::TertiaryMid]]; }
.TertiaryDark { color:[[ColorPalette::TertiaryDark]]; }
.Error { color:[[ColorPalette::Error]]; }
/* [[ColorPalette]] background colors */
.BGBackground { background-color:[[ColorPalette::Background]]; }
.BGForeground { background-color:[[ColorPalette::Foreground]]; }
.BGPrimaryPale { background-color:[[ColorPalette::PrimaryPale]]; }
.BGPrimaryLight { background-color:[[ColorPalette::PrimaryLight]]; }
.BGPrimaryMid { background-color:[[ColorPalette::PrimaryMid]]; }
.BGPrimaryDark { background-color:[[ColorPalette::PrimaryDark]]; }
.BGSecondaryPale { background-color:[[ColorPalette::SecondaryPale]]; }
.BGSecondaryLight { background-color:[[ColorPalette::SecondaryLight]]; }
.BGSecondaryMid { background-color:[[ColorPalette::SecondaryMid]]; }
.BGSecondaryDark { background-color:[[ColorPalette::SecondaryDark]]; }
.BGTertiaryPale { background-color:[[ColorPalette::TertiaryPale]]; }
.BGTertiaryLight { background-color:[[ColorPalette::TertiaryLight]]; }
.BGTertiaryMid { background-color:[[ColorPalette::TertiaryMid]]; }
.BGTertiaryDark { background-color:[[ColorPalette::TertiaryDark]]; }
.BGError { background-color:[[ColorPalette::Error]]; }
/*}}}*/
/***
|Name|TableOfContentsPlugin|
|Source|http://www.TiddlyTools.com/#TableOfContentsPlugin|
|Documentation|http://www.TiddlyTools.com/#TableOfContentsPluginInfo|
|Version|2.4.3|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|replace the standard tabbed contents list with a scrolling listbox|
When there are many tiddlers in a document, the standard 'tabbed list of tiddlers' in the right-hand sidebar can become very long, occupying a lot of page space and requiring a lot scrolling in order to locate and select a tiddler. The TableOfContentsPlugin addresses this problem by replacing the standard tabbed list display with a single listbox/droplist control that uses a very small amount of page space, regardless of the number of tiddlers in the document.
!!!!!Documentation
>see [[TableOfContentsPluginInfo]]
!!!!!Configuration
<<option chkTOCShow>> display table of contents listbox
<<option chkTOCIncludeHidden>> include tiddlers tagged with <<tag excludeLists>> in listbox
listbox shows <<option txtTOCListSize>> lines, sorted by <<option txtTOCSortBy>>
!!!!!Revisions
<<<
2008.04.09 [2.4.3] restored config.options.chkTOCShow and onClickTOCMenu() handler
|please see [[TableOfContentsPluginInfo]] for additional revision details|
2005.06.13 [1.0.0] Initial Release (as adaptation - predates TiddlyWiki plugin architecture!!)
<<<
!!!!!Code
***/
//{{{
version.extensions.tableOfContents = {major: 2, minor: 4, revision: 3, date: new Date(2008,4,9)};
//}}}
// // 1.2.x compatibility
//{{{
if (!window.story) window.story=window;
if (!store.getTiddler) store.getTiddler=function(title){return store.tiddlers[title]}
if (!store.addTiddler) store.addTiddler=function(tiddler){store.tiddlers[tiddler.title]=tiddler}
if (!store.deleteTiddler) store.deleteTiddler=function(title){delete store.tiddlers[title]}
//}}}
//{{{
// define defaults for cookie-based option values
if (config.options.txtTOCSortBy==undefined) config.options.txtTOCSortBy="modified";
if (config.options.txtTOCListSize==undefined) config.options.txtTOCListSize=19;
if (config.options.chkTOCShow==undefined) config.options.chkTOCShow=true;
if (config.options.chkTOCIncludeHidden==undefined) config.options.chkTOCIncludeHidden=false;
// define macro "tableOfContents" to render controls
config.macros.tableOfContents = { label: "contents" };
config.macros.tableOfContents.cmdMax=8; // index of maximum command item
config.macros.tableOfContents.css = '\
.TOC { padding:0.5em 1em 0.5em 1em; }\
.TOC a { padding:0em 0.25em 0em 0.25em; color:inherit; }\
.TOCList { width: 100%; font-size:8pt; margin:0em; }\
';
config.macros.tableOfContents.html = '\
<div style="text-align:right">\
<span style="float:left">\
<a href="JavaScript:;" id="TOCMenu" style="padding: 0em;"\
onclick="onClickTOCMenu(this)" title="show/hide table of contents">%label%</a>\
</span>\
<a href="JavaScript:;" id="TOCSmaller" style="display:inline"\
onclick="resizeTOC(this)" title="reduce list size">–</a>\
<a href="JavaScript:;" id="TOCLarger"style="display:inline"\
onclick="resizeTOC(this)" title="increase list size">+</a>\
<a href="JavaScript:;" id="TOCMaximize"style="display:inline"\
onclick="resizeTOC(this)" title="maximize/restore list size">=</a>\
</div>\
';
config.macros.tableOfContents.handler = function(place,macroName,params) {
var parsedParams = new Array();
parsedParams['label']=this.label;
parsedParams['inline']=false;
while (params.length>0) {
if (params[0]=="label:none") parsedParams['label']="";
else if (params[0].substr(0,6)=="label:") parsedParams['label']=params[0].substr(6);
if (params[0].substr(0,7)=="prompt:") parsedParams['prompt']=params[0].substr(7);
if (params[0].substr(0,8)=="padding:")parsedParams['padding']=params[0].substr(8);
if (params[0].substr(0,7)=="margin:") parsedParams['margin']=params[0].substr(7);
if (params[0].substr(0,5)=="sort:") parsedParams['sortby']=params[0].substr(5);
if (params[0].substr(0,5)=="date:") parsedParams['date']=params[0].substr(5);
if ((params[0]=="size:auto")||(params[0]=="size:0")) parsedParams['autosize']=true;
else if (params[0] && (params[0].substr(0,5)=="size:")) parsedParams['requestedSize']=params[0].substr(5);
if (params[0].substr(0,6)=="width:") parsedParams['width']=params[0].substr(6);
if (params[0]=="hidelist") parsedParams['hidelist']=true;
if (params[0]=="inline") parsedParams['inline']=true;
if (params[0]=="-title") parsedParams['hide_title']=true;
if (params[0]=="-date") parsedParams['hide_date']=true;
if (params[0]=="-author") parsedParams['hide_author']=true;
if (params[0]=="-creator") parsedParams['hide_creator']=true;
if (params[0]=="-tags") parsedParams['hide_tags']=true;
if (params[0]=="-missing") parsedParams['hide_missing']=true;
if (params[0]=="-orphans") parsedParams['hide_orphans']=true;
if (params[0]=="-shadows") parsedParams['hide_shadows']=true;
params.shift();
}
setStylesheet(config.macros.tableOfContents.css,"tableOfContents");
var newTOC=createTiddlyElement(place,parsedParams['inline']?"span":"div",null,"TOC",null)
if (parsedParams['margin']) { newTOC.style.margin=parsedParams['margin']; }
if (parsedParams['padding']) { newTOC.style.padding=parsedParams['padding']; }
if (parsedParams['label']!="") newTOC.innerHTML=config.macros.tableOfContents.html.replace(/%label%/,parsedParams['label']);
var newTOCList=createTOCList(newTOC,parsedParams)
refreshTOCList(newTOCList);
store.addNotification(null,reloadTOCLists); // reload listbox after every tiddler change
}
// IE needs explicit global scoping for functions/vars called from browser events
window.onChangeTOCList=onChangeTOCList;
window.onClickTOCList=onClickTOCList;
window.onDblClickTOCList=onDblClickTOCList;
window.reloadTOCLists=reloadTOCLists;
window.refreshTOCList=refreshTOCList;
window.onClickTOCMenu=onClickTOCMenu;
window.resizeTOC=resizeTOC;
function createTOCList(place,params) {
var list = createTiddlyElement(place,"select",null,"TOCList",params['prompt'])
list.params=params;
list.onchange=onChangeTOCList;
list.onclick=onClickTOCList;
list.ondblclick=onDblClickTOCList;
list.onkeyup=onKeyUpTOCList;
list.style.display=config.options.chkTOCShow ? "block" : "none" ;
list.sortBy=config.options.txtTOCSortBy;
list.dateFormat="DD MMM YYYY";
list.requestedSize=config.options.txtTOCListSize;
list.expandall=false;
list.cmdMax=config.macros.tableOfContents.cmdMax;
if (params['hide_title']) list.cmdMax--;
if (params['hide_date']) list.cmdMax--;
if (params['hide_author']) list.cmdMax--;
if (params['hide_creator']) list.cmdMax--;
if (params['hide_tags']) list.cmdMax--;
if (params['hide_missing']) list.cmdMax--;
if (params['hide_orphans']) list.cmdMax--;
if (params['hide_shadows']) list.cmdMax--;
if (params['sortby']) { list.sortBy=params['sortby']; list.noSortCookie=true; }
if (params['date']) { list.dateFormat=params['date']; }
if (params['autosize']) { list.autosize=true; list.noSizeCookie=true; }
if (params['requestedSize']){ list.requestedSize=params['requestedSize']; list.noSizeCookie=true; }
if (params['width']) { list.style.width=params['width']; }
if (params['hidelist']) { list.style.display ="none" ; list.noShowCookie=true; }
if (params['expandall']) { list.expandall=true; }
return list;
}
function onChangeTOCList() {
var thisTiddler=this.options[this.selectedIndex].value;
if ((this.size==1)&&(thisTiddler!='')&&(this.selectedIndex>this.cmdMax))
story.displayTiddler(null,thisTiddler,1);
refreshTOCList(this);
return false;
}
function onClickTOCList(e) {
if (!e) var e = window.event;
if (this.size==1) return; // don't toggle display for droplist
if (e.shiftKey) { this.expandall=!this.expandall; refreshTOCList(this);}
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
return true;
}
function onDblClickTOCList(e) {
if (!e) var e = window.event;
var thisTiddler=this.options[this.selectedIndex].value;
if ((thisTiddler!='')&&(this.selectedIndex>this.cmdMax))
story.displayTiddler(null,thisTiddler,1);
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
return false;
}
function onKeyUpTOCList(e) {
if (!e) var e = window.event;
if (e.keyCode!=13) return true;
var thisTiddler=this.options[this.selectedIndex].value;
if ((thisTiddler!='')&&(this.selectedIndex>this.cmdMax))
story.displayTiddler(null,thisTiddler,1);
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
return false;
}
function reloadTOCLists() {
var all=document.all? document.all.tags("select") : document.getElementsByTagName("select");
for (var i=0; i<all.length; i++)
if (all[i].className=="TOCList")
{ all[i].selectedIndex=-1; refreshTOCList(all[i]); }
}
function refreshTOCList(list) {
var selectedIndex = list.selectedIndex;
if (selectedIndex==-1) selectedIndex=0;
var sortBy = list.sortBy;
var showHidden = config.options.chkTOCIncludeHidden && !(config.options.chkHttpReadOnly && readOnly);
if (selectedIndex==0) sortBy=list.sortBy; // "nnn tiddlers" heading - use previous sort order
else if (selectedIndex<=list.cmdMax)sortBy=list.value;
else { if (list.options[list.selectedIndex].value=='') expandTOC(list); return; }
list.sortBy = sortBy; // save current sort order
if (!list.noSortCookie) { config.options.txtTOCSortBy=sortBy; saveOptionCookie("txtTOCSortBy"); }
// get the list of tiddlers
var tiddlers = [];
switch (sortBy) {
case "missing": tiddlers=store.getMissingLinks(); break;
case "tags": tiddlers=store.getTags(); break;
case "orphans": tiddlers=store.getOrphans(); break;
case "shadows": for (var t in config.shadowTiddlers) tiddlers.push(t); tiddlers.sort(); break;
default: tiddlers=store.getTiddlers(sortBy=='creator'?'modifier':sortBy,showHidden?'':'excludeLists'); break;
}
// clear current listbox contents
while (list.length > 0) { list.options[0] = null; }
list.saved=null;
// add heading and control items to list
var i=0;
var theHeading=tiddlers.length+' tiddlers:';
if (sortBy=='missing') theHeading=tiddlers.length+' missing tiddlers:';
if (sortBy=='orphans') theHeading=tiddlers.length+' orphaned tiddlers:';
if (sortBy=='tags') theHeading=tiddlers.length+' tags:';
if (sortBy=='shadows') theHeading=tiddlers.length+' shadow tiddlers:';
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var sel=">";
list.options[i++]=new Option(theHeading,'');
function headerOpt(txt,val) { return new Option(((sortBy==val)?sel:indent)+' ['+txt+']',val); }
if (!list.params['hide_title']) list.options[i++]=headerOpt('by title','title');
if (!list.params['hide_date']) list.options[i++]=headerOpt('by date','modified');
if (!list.params['hide_author']) list.options[i++]=headerOpt('by author','modifier');
if (!list.params['hide_creator']) list.options[i++]=headerOpt('by creator','creator');
if (!list.params['hide_tags']) list.options[i++]=headerOpt('by tags','tags');
if (!list.params['hide_missing']) list.options[i++]=headerOpt('missing','missing');
if (!list.params['hide_orphans']) list.options[i++]=headerOpt('orphans','orphans');
if (!list.params['hide_shadows']) list.options[i++]=headerOpt('shadows','shadows');
// output the tiddler list
switch(sortBy) {
case "title":
for (var t = 0; t < tiddlers.length; t++)
list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title);
break;
case "modified":
case "modifier":
case "creator":
if (sortBy=="modified") tiddlers.reverse(); // show newest first
if (sortBy=="creator") { // sort by custom field with fallback value
tiddlers.sort(function (a,b) {
var v1=a.fields.creator||a.modifier;
var v2=b.fields.creator||b.modifier;
return (v1==v2)?0:(v1>v2?1:-1);
});
}
var lastSection = "";
for (var t = 0; t < tiddlers.length; t++){
var tiddler = tiddlers[t];
var theSection = "";
var m=tiddler.modified;
if (sortBy=="modified") theSection=m.getFullYear()+'.'+(m.getMonth()+1)+'.'+m.getDate();
if (sortBy=="modifier") theSection = tiddler.modifier;
if (sortBy=="creator") theSection=tiddler.fields['creator']||tiddler.modifier;
if (theSection != lastSection) {
lastSection = theSection;
if (sortBy=="modified") theSection = m.formatString(list.dateFormat);
list.options[i++] = new Option('+ '+theSection,"");
}
list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title);
}
expandTOC(list);
break;
case "tags":
// tagged tiddlers, by tag
var tagcount=0;
var lastTag = null;
for (var t = 0; t < tiddlers.length; t++) { // actually a list of tags, not tiddlers...
var theTag = tiddlers[t][0]; var tid=store.getTiddler(theTag);
if (tid && tid.isTagged('excludeLists')) continue; // skip excluded tags
var temp = store.getTaggedTiddlers(theTag);
var tagged=[]; for (var q=0; q<temp.length; q++) // hide excluded tiddlers
if (!temp[q].isTagged('excludeLists')) tagged.push(temp[q]);
if (tagged.length) { tagcount++;
list.options[i++]=new Option('+ '+theTag+" ("+tagged.length+")","");
for(var r=0; r<tagged.length; r++)
list.options[i++]=
new Option(indent+indent+tagged[r].title,tagged[r].title);
}
}
// count untagged tiddlers
var temp = store.getTiddlers("title");
var c=0; for (var r=0; r<temp.length;r++) if (!temp[r].tags.length) c++;
// create 'pseudo-tag' listing untagged tiddlers (if any)
if (c>0) {
list.options[i++] = new Option("+ untagged ("+c+")","");
for (var r=0; r<temp.length;r++) if (!temp[r].tags.length)
list.options[i++] = new
Option(indent+indent+temp[r].title,temp[r].title);
}
list.options[0].text=tagcount+' tags:';
expandTOC(list);
break;
case "missing": case "orphans": case "shadows":
for (var t = 0; t < tiddlers.length; t++)
list.options[i++] = new Option(tiddlers[t],tiddlers[t]);
break;
}
list.selectedIndex=selectedIndex; // select current control item
list.size = (list.autosize)?list.options.length:list.requestedSize;
}
// show/hide branch of TOCList based on current selection
function expandTOC(list) {
var selectedIndex = list.selectedIndex;
if (selectedIndex==-1) selectedIndex=0;
var sortBy = list.sortBy;
// don't collapse/expand list for alpha-sorted "flatlist" TOC contents
// or list control items
if ((sortBy=="title")||(sortBy=="missing")||(sortBy=="orphans")||(sortBy=="shadows")) return;
if ((selectedIndex>0)&&(selectedIndex<=list.cmdMax)) return;
// get current selected text/value and cache the
// complete list. Then clear the current list contents
var theText = list.options[selectedIndex].text;
var theValue = list.options[selectedIndex].value;
if (!list.saved) {
list.saved=new Array();
for (var i=0;i<list.length;i++) list.saved[i]=list.options[i];
}
while (list.length > 0) { list.options[0] = null; }
// put back heading items until item text matches current selected heading
var i=0;
for (var t=0; t<list.saved.length; t++) {
var opt=list.saved[t];
if (list.expandall||(opt.value=='')||(i<=list.cmdMax)) list.options[i++] = opt;
if (opt.text==theText) break;
}
selectedIndex=i-1; // this is the NEW index of the current selected heading
// put back items with value!='' until value==''
for ( t++; t<list.saved.length; t++) {
var opt=list.saved[t];
if (list.expandall||opt.value!='') list.options[i++] = opt;
if (opt.value=='') break;
}
// put back remaining items with value==''
for ( ; t<list.saved.length; t++) {
var opt=list.saved[t];
if (list.expandall||opt.value=='') list.options[i++] = opt;
}
list.selectedIndex = selectedIndex;
list.size = (list.autosize)?list.options.length:list.requestedSize;
}
// these functions process clicks on the 'control links' that are displayed above the listbox
function getTOCListFromButton(which) {
var list = null;
switch (which.id) {
case 'TOCMenu':
var theSiblings = which.parentNode.parentNode.parentNode.childNodes;
var thePlace=which.parentNode.parentNode.parentNode.parentNode.parentNode.id;
break;
case 'TOCSmaller': case 'TOCLarger': case 'TOCMaximize':
var theSiblings = which.parentNode.parentNode.childNodes;
var thePlace=which.parentNode.parentNode.parentNode.parentNode.id;
break;
}
for (var k=0; k<theSiblings.length; k++)
if (theSiblings[k].className=="TOCList") { list=theSiblings[k]; break; }
return list;
}
function onClickTOCMenu(which) {
var list=getTOCListFromButton(which); if (!list) return;
var opening = list.style.display=="none";
if(config.options.chkAnimate) anim.startAnimating(new Slider(list,opening,false,"none"));
else list.style.display = opening ? "block" : "none" ;
if (!list.noShowCookie) { config.options.chkTOCShow = opening; saveOptionCookie("chkTOCShow"); }
return(false);
}
function resizeTOC(which) {
var list=getTOCListFromButton(which); if (!list) return;
var size = list.size;
if (list.style.display=="none") // make sure list is visible
if(config.options.chkAnimate) anim.startAnimating(new Slider(list,true,false,"none"));
else list.style.display = "block" ;
switch (which.id) {
case 'TOCSmaller': // decrease current listbox size
if (list.autosize) { list.autosize=false; size=config.options.txtTOCListSize; }
if (size==1) break;
size -= 1; // shrink by one line
list.requestedSize = list.size = size;
break;
case 'TOCLarger': // increase current listbox size
if (list.autosize) { list.autosize=false; size=config.options.txtTOCListSize; }
if (size>=list.options.length) break;
size += 1; // grow by one line
list.requestedSize = list.size = size;
break;
case 'TOCMaximize': // toggle autosize
list.autosize = (list.size!=list.options.length);
list.size = (list.autosize)?list.options.length:list.requestedSize;
break;
}
if (!list.noSizeCookie && !list.autosize)
{ config.options.txtTOCListSize=size; saveOptionCookie("txtTOCListSize"); }
}
//}}}
/***
|''Name:''|TableSortingPlugin|
|''Description:''|Dynamically sort tables by clicking on column headers|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TableSortingPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.02|
|''Date:''|25-01-2008|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|
!!Usage:
* Make sure your table has a header row
** {{{|Name|Phone Number|Address|h}}}<br> Note the /h/ that denote a header row
* Give the table a class of 'sortable'
** {{{
|sortable|k
|Name|Phone Number|Address|h
}}}<br>Note the /k/ that denotes a class name being assigned to the table.
* To disallow sorting by a column, place {{{<<nosort>>}}} in it's header
* To automatically sort a table by a column, place {{{<<autosort>>}}} in the header for that column
** Or to sort automatically but in reverse order, use {{{<<autosort reverse>>}}}
!!Example:
|sortable|k
|Name |Salary |Extension |Performance |File Size |Start date |h
|ZBloggs, Fred |$12000.00 |1353 |+1.2 |74.2Kb |Aug 19, 2003 21:34:00 |
|ABloggs, Fred |$12000.00 |1353 |1.2 |3350b |09/18/2003 |
|CBloggs, Fred |$12000 |1353 |1.200 |55.2Kb |August 18, 2003 |
|DBloggs, Fred |$12000.00 |1353 |1.2 |2100b |07/18/2003 |
|Bloggs, Fred |$12000.00 |1353 |01.20 |6.156Mb |08/17/2003 05:43 |
|Turvey, Kevin |$191200.00 |2342 |-33 |1b |02/05/1979 |
|Mbogo, Arnold |$32010.12 |2755 |-21.673 |1.2Gb |09/08/1998 |
|Shakespeare, Bill |£122000.00|3211 |6 |33.22Gb |12/11/1961 |
|Shakespeare, Hamlet |£9000 |9005 |-8 |3Gb |01/01/2002 |
|Fitz, Marvin |€3300.30 |5554 |+5 |4Kb |05/22/1995 |
***/
// /%
//!BEGIN-PLUGIN-CODE
config.tableSorting = {
darrow: "\u2193",
uarrow: "\u2191",
getText : function (o) {
var p = o.cells[SORT_INDEX];
return p.innerText || p.textContent || '';
},
sortTable : function (o,rev) {
SORT_INDEX = o.getAttribute("index");
var c = config.tableSorting;
var T = findRelated(o.parentNode,"TABLE");
if(T.tBodies[0].rows.length<=1)
return;
var itm = "";
var i = 0;
while (itm == "" && i < T.tBodies[0].rows.length) {
itm = c.getText(T.tBodies[0].rows[i]).trim();
i++;
}
if (itm == "")
return;
var r = [];
var S = o.getElementsByTagName("span")[0];
c.fn = c.sortAlpha;
if(!isNaN(Date.parse(itm)))
c.fn = c.sortDate;
else if(itm.match(/^[$|£|€|\+|\-]{0,1}\d*\.{0,1}\d+$/))
c.fn = c.sortNumber;
else if(itm.match(/^\d*\.{0,1}\d+[K|M|G]{0,1}b$/))
c.fn = c.sortFile;
for(i=0; i<T.tBodies[0].rows.length; i++) {
r[i]=T.tBodies[0].rows[i];
}
r.sort(c.reSort);
if(S.firstChild.nodeValue==c.darrow || rev) {
r.reverse();
S.firstChild.nodeValue=c.uarrow;
}
else
S.firstChild.nodeValue=c.darrow;
var thead = T.getElementsByTagName('thead')[0];
var headers = thead.rows[thead.rows.length-1].cells;
for(var k=0; k<headers.length; k++) {
if(!hasClass(headers[k],"nosort"))
addClass(headers[k].getElementsByTagName("span")[0],"hidden");
}
removeClass(S,"hidden");
for(i=0; i<r.length; i++) {
T.tBodies[0].appendChild(r[i]);
c.stripe(r[i],i);
for(var j=0; j<r[i].cells.length;j++){
removeClass(r[i].cells[j],"sortedCol");
}
addClass(r[i].cells[SORT_INDEX],"sortedCol");
}
},
stripe : function (e,i){
var cl = ["oddRow","evenRow"];
i&1? cl.reverse() : cl;
removeClass(e,cl[1]);
addClass(e,cl[0]);
},
sortNumber : function(v) {
var x = parseFloat(this.getText(v).replace(/[^0-9.-]/g,''));
return isNaN(x)? 0: x;
},
sortDate : function(v) {
return Date.parse(this.getText(v));
},
sortAlpha : function(v) {
return this.getText(v).toLowerCase();
},
sortFile : function(v) {
var j, q = config.messages.sizeTemplates, s = this.getText(v);
for (var i=0; i<q.length; i++) {
if ((j = s.toLowerCase().indexOf(q[i].template.replace("%0\u00a0","").toLowerCase())) != -1)
return q[i].unit * s.substr(0,j);
}
return parseFloat(s);
},
reSort : function(a,b){
var c = config.tableSorting;
var aa = c.fn(a);
var bb = c.fn(b);
return ((aa==bb)? 0 : ((aa<bb)? -1:1));
}
};
Story.prototype.tSort_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText){
var elem = this.tSort_refreshTiddler.apply(this,arguments);
if(elem){
var tables = elem.getElementsByTagName("TABLE");
var c = config.tableSorting;
for(var i=0; i<tables.length; i++){
if(hasClass(tables[i],"sortable")){
var x = null, rev, table = tables[i], thead = table.getElementsByTagName('thead')[0], headers = thead.rows[thead.rows.length-1].cells;
for (var j=0; j<headers.length; j++){
var h = headers[j];
if (hasClass(h,"nosort"))
continue;
h.setAttribute("index",j);
h.onclick = function(){c.sortTable(this); return false;};
h.ondblclick = stopEvent;
if(h.getElementsByTagName("span").length == 0)
createTiddlyElement(h,"span",null,"hidden",c.uarrow);
if(!x && hasClass(h,"autosort")) {
x = j;
rev = hasClass(h,"reverse");
}
}
if(x)
c.sortTable(headers[x],rev);
}
}
}
return elem;
};
setStylesheet("table.sortable span.hidden {visibility:hidden;}\n"+
"table.sortable thead {cursor:pointer;}\n"+
"table.sortable .nosort {cursor:default;}\n"+
"table.sortable td.sortedCol {background:#ffc;}","TableSortingPluginStyles");
function stopEvent(e){
var ev = e? e : window.event;
ev.cancelBubble = true;
if (ev.stopPropagation) ev.stopPropagation();
return false;
}
config.macros.nosort={
handler : function(place){
addClass(place,"nosort");
}
};
config.macros.autosort={
handler : function(place,m,p,w,pS){
addClass(place,"autosort"+" "+pS);
}
};
//!END-PLUGIN-CODE
// %/
/***
|Name:|TagglyTaggingPlugin|
|Description:|tagglyTagging macro is a replacement for the builtin tagging macro in your ViewTemplate|
|Version:|3.3.1 ($Rev: 6100 $)|
|Date:|$Date: 2008-07-27 01:42:07 +1000 (Sun, 27 Jul 2008) $|
|Source:|http://mptw.tiddlyspot.com/#TagglyTaggingPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
See http://mptw.tiddlyspot.com/#TagglyTagging
***/
//{{{
merge(String.prototype,{
parseTagExpr: function(debug) {
if (this.trim() == "")
return "(true)";
var anyLogicOp = /(!|&&|\|\||\(|\))/g;
var singleLogicOp = /^(!|&&|\|\||\(|\))$/;
var spaced = this.
// because square brackets in templates are no good
// this means you can use [(With Spaces)] instead of [[With Spaces]]
replace(/\[\(/g," [[").
replace(/\)\]/g,"]] ").
// space things out so we can use readBracketedList. tricky eh?
replace(anyLogicOp," $1 ");
var expr = "";
var tokens = spaced.readBracketedList(false); // false means don't uniq the list. nice one JR!
for (var i=0;i<tokens.length;i++)
if (tokens[i].match(singleLogicOp))
expr += tokens[i];
else
expr += "tiddler.tags.contains('%0')".format([tokens[i].replace(/'/,"\\'")]); // fix single quote bug. still have round bracket bug i think
if (debug)
alert(expr);
return '('+expr+')';
}
});
merge(TiddlyWiki.prototype,{
getTiddlersByTagExpr: function(tagExpr,sortField) {
var result = [];
var expr = tagExpr.parseTagExpr();
store.forEachTiddler(function(title,tiddler) {
if (eval(expr))
result.push(tiddler);
});
if(!sortField)
sortField = "title";
result.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
return result;
}
});
config.taggly = {
// for translations
lingo: {
labels: {
asc: "\u2191", // down arrow
desc: "\u2193", // up arrow
title: "title",
modified: "modified",
created: "created",
show: "+",
hide: "-",
normal: "normal",
group: "group",
commas: "commas",
sitemap: "sitemap",
numCols: "cols\u00b1", // plus minus sign
label: "Tagged as '%0':",
exprLabel: "Matching tag expression '%0':",
excerpts: "excerpts",
descr: "descr",
slices: "slices",
contents: "contents",
sliders: "sliders",
noexcerpts: "title only",
noneFound: "(none)"
},
tooltips: {
title: "Click to sort by title",
modified: "Click to sort by modified date",
created: "Click to sort by created date",
show: "Click to show tagging list",
hide: "Click to hide tagging list",
normal: "Click to show a normal ungrouped list",
group: "Click to show list grouped by tag",
sitemap: "Click to show a sitemap style list",
commas: "Click to show a comma separated list",
numCols: "Click to change number of columns",
excerpts: "Click to show excerpts",
descr: "Click to show the description slice",
slices: "Click to show all slices",
contents: "Click to show entire tiddler contents",
sliders: "Click to show tiddler contents in sliders",
noexcerpts: "Click to show entire title only"
},
tooDeepMessage: "* //sitemap too deep...//"
},
config: {
showTaggingCounts: true,
listOpts: {
// the first one will be the default
sortBy: ["title","modified","created"],
sortOrder: ["asc","desc"],
hideState: ["show","hide"],
listMode: ["normal","group","sitemap","commas"],
numCols: ["1","2","3","4","5","6"],
excerpts: ["noexcerpts","excerpts","descr","slices","contents","sliders"]
},
valuePrefix: "taggly.",
excludeTags: ["excludeLists","excludeTagging"],
excerptSize: 50,
excerptMarker: "/%"+"%/",
siteMapDepthLimit: 25
},
getTagglyOpt: function(title,opt) {
var val = store.getValue(title,this.config.valuePrefix+opt);
return val ? val : this.config.listOpts[opt][0];
},
setTagglyOpt: function(title,opt,value) {
if (!store.tiddlerExists(title))
// create it silently
store.saveTiddler(title,title,config.views.editor.defaultText.format([title]),config.options.txtUserName,new Date(),"");
// if value is default then remove it to save space
return store.setValue(title,
this.config.valuePrefix+opt,
value == this.config.listOpts[opt][0] ? null : value);
},
getNextValue: function(title,opt) {
var current = this.getTagglyOpt(title,opt);
var pos = this.config.listOpts[opt].indexOf(current);
// a little usability enhancement. actually it doesn't work right for grouped or sitemap
var limit = (opt == "numCols" ? store.getTiddlersByTagExpr(title).length : this.config.listOpts[opt].length);
var newPos = (pos + 1) % limit;
return this.config.listOp