Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
*1ste Kan Inf
**Imperatief Programmeren II: Programmeren in C
**Computersystemen
*2e Kan Inf
**~Object-Georienteerd Programmeren
**Project ~Object-Georienteerd Programmeren en Algoritmen en Datastructuren
**Project 2IK
*1ste Lic Inf
**Project 3.3
*2e Lic Inf
**Software Engineering
*Thesisstudenten
**Danny Laarmans, "//Collision Response for Physically Realistic Simulation of Rigid Bodies//"
**Niels Soeffers, "//Een Overzicht en Vergelijking van Populaire Technieken bij Cloth Simulation//"
*1ste Kan Inf
**Imperatief Programmeren II: Programmeren in C
*2e Kan Inf
**~Object-Georienteerd Programmeren
**Project ~Object-Georienteerd Programmeren en Algoritmen en Datastructuren
**Project 2IK
*1ste Lic Inf
**Computeranimatie
**Project 3.3
*2e Lic Inf
**Software Engineering
*Thesisstudenten
**Tom Moers, "//Constraints in Physically-based Simulations//"
*1ste Bach. Inf/ICT
**Imperatief Programmeren II: Programmeren in C
*2e Bach. Inf/ICT
**~Object-Georienteerd Programmeren
**Project ~Object-Georienteerd Programmeren en Algoritmen en Datastructuren
**Project 2IK
*3de Kan. Inf
**Computeranimatie
**Project 3.3
*2e Lic Inf
**Architectuur en Algoritmes van Computer Games
**Project 4.1
**Software Engineering
*Thesisstudenten
**Davy Renaers, "//Virtual Brush//"
**Kristof Thys, "//Simulatie van Natuurlijke Phenomenen met behulp van Cellulaire Automaten//"
**John Opdenakker, "//Collision Detection in ~CVEs//"
*1ste Bach. Inf/ICT
**Imperatief Programmeren II: Programmeren in C
*2e Bach. Inf/ICT
**~Object-Georienteerd Programmeren
**Project ~Object-Georienteerd Programmeren en Algoritmen en Datastructuren
**Project 2IK
*3de Bach. Inf
**Project
**Software Engineering
*2e Lic Inf
**Architectuur en Algoritmes van Computer Games
**Project 4.1
*MIT
**Multimedia en Communicatietechnologie
*Thesisstudenten
**Dirk Vanden Boer, "//General-purpose Computing on ~GPUs//"
*1ste Bach. Inf/ICT
**Imperatief Programmeren II: Programmeren in C ([[website|http://didactiekinf.uhasselt.be/impprog2]])
*2e Bach. Inf/ICT
**~Object-Georienteerd Programmeren ([[website|http://didactiekinf.uhasselt.be/oo]])
**Project ~Object-Georienteerd Programmeren en Algoritmen en Datastructuren
**Project 2IK ([[website|http://didactiekinf.uhasselt.be/project2]])
**Geavanceerde Programmeertechnieken ([[website|http://didactiekinf.uhasselt.be/gpt]])
*3de Bach. Inf/ICT
**Software Engineering ([[website|http://didactiekinf.uhasselt.be/se]])
*Master Inf
**Architectuur en Algoritmes van Computer Games ([[website|http://didactiekinf.uhasselt.be/aac]])
**Computeranimatie ([[website|http://didactiekinf.uhasselt.be/animatie]])
**Geavanceerde Software Engineering ([[website|http://didactiekinf.uhasselt.be/gse]])
*MIT
**Multimedia en Communicatietechnologie
*Thesisstudenten
**Bart Ameloot, "//Watercolorization//"
*2e Bach. Inf/ICT
**Trimesteroverschrijdend Project ([[website|http://didactiekinf.uhasselt.be/project2]])
*3de Bach. Inf/ICT
**Software Engineering ([[website|http://didactiekinf.uhasselt.be/se]])
*Master Inf
**Architectuur en Algoritmes van Computer Games ([[website|http://didactiekinf.uhasselt.be/aac]])
**Computeranimatie ([[website|http://didactiekinf.uhasselt.be/animatie]])
**Geavanceerde Software Engineering ([[website|http://didactiekinf.uhasselt.be/gse]])
*Thesisstudenten
**Kemal Taskin, "//High Resolution Simulation Output//"
**Brecht Van Lommel, "//Painterly Animation//"
*2e Bach. Inf/ICT
**Trimesteroverschrijdend Project ([[website|http://didactiekinf.uhasselt.be/project2]])
*3de Bach. Inf/ICT
**Software Engineering ([[website|http://didactiekinf.uhasselt.be/se]])
*Master Inf
**Capita Selecta van de Multimedia ([[website|http://didactiekinf.uhasselt.be/capita]])
**Architectuur en Algoritmes van Computer Games ([[website|http://didactiekinf.uhasselt.be/aac]])
**Computeranimatie ([[website|http://didactiekinf.uhasselt.be/animatie]])
**Geavanceerde Software Engineering ([[website|http://didactiekinf.uhasselt.be/gse]])
*Thesisstudenten
**Brecht Van Lommel, "//Diļ¬erential Methods in Character Rigging//"
**Tom Ameloot, "//Painterly Animation//"
*2e Bach. Inf/ICT
**Trimesteroverschrijdend Project ([[website|http://didactiekinf.uhasselt.be/project2]])
*3de Bach. Inf/ICT
**Software Engineering ([[website|http://didactiekinf.uhasselt.be/se]])
*Master Inf
**Capita Selecta van de Multimedia ([[website|http://didactiekinf.uhasselt.be/capita]])
**Architectuur en Algoritmes van Computer Games ([[website|http://didactiekinf.uhasselt.be/aac]])
**Computeranimatie ([[website|http://didactiekinf.uhasselt.be/animatie]])
**Geavanceerde Software Engineering ([[website|http://didactiekinf.uhasselt.be/gse]])
A simple, interactive application that implements the 2D ~Navier-Stokes wave equation in C++, with a Qt interface to tweak some parameters. The implementation is based on the paper "[[Realistic Animation of Liquids|http://www.cis.upenn.edu/~fostern/pdfs/gmip96.pdf]]", from Nick Foster and Dimitri Metaxas (SIGGRAPH '96).
* [[navierstokes2d_v001.tar.gz|./projects/navierstokes2d_v001.tar.gz]] (20-06-03)
Note: Using an explicit Eulerian integrator, the current implementation is unstable!
A dutch document ([[ps|./projects/navierstokesvgl.ps]]) by Jori Liesenborgs describing the derivation of the ~Navier-Stokes equations from Jos Stam's "Stable Fluids" paper to Foster's "Realistic Animation of Liquids".
Encrypted(D4AB314997B43D77229C56C518D29A8D0B9612BD)
6a88a3e6da3adbdc15a121333921ecdb895e6394456b971088f947ab7410a56f39
b74f38a9326492f271d7e579c007532a3564b1d5f11ca4016d7a53389a265f59
51e532e3c1ba8b2f7c8c8f071601bcd93810eb1a96a4f8e51f5b959cadc442a6
67c96832ef88ec186b7f7035619668ee266b8dab19c3696a3c298551be213133
216838babadb3f6885a105c1413829213339215e781b0f5654ac4e864c08b56c
856c50e320f141bfb5e33e8221313321d48c2f9a01ced06d668f5f78d12ace1d
a5fd4aab6bfef35a05575fbf8fa2d02bcd979a3a1817da77a537e5aa3586a9fc
8c060f2131363021e679ba213131214ae690bee2aad99eff9f1a857d21313321
f2aa213136302115e8a6213132217bffe3df50d3522f04c45d213130216c2139
21d0fffe2b8d90501eafdf51d172a8a63321333921579ee119840e7046a1f67d
e3104474565ba48a403031b8dd937a16c6d03dc67a7f5821333421b0f9896c21
3131219692f09901d79032629b0e7d90ab08ea2468c8e1dcd320856c700e8ce2
33eb6121313121e58895973c024867d40457193e5abe5c21302121313321f36b
21333421df19fd31041361571a986695a95ecd7a770e698e2636efb05d8ea95e
e7687c2c75fb7fd557213131213a60369a84f9f6859a78ce21333921a320942b
984223faea5f0663315821313630214a03cf56
/***
|Name|BreadcrumbsPlugin|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|1.8.2|
|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|
|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 chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
<<<
!!!!!Revisions
<<<
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 [1.8.2] documentation cleanup
| Please see [[BreadcrumbsPluginInfo]] for previous revision details |
2006.02.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.breadCrumbs = {major: 1, minor: 8, revision: 2, date: new Date("Oct 26, 2007")};
// show/hide display option (default is to SHOW breadcrumbs)
if (config.options.chkShowBreadcrumbs==undefined)
config.options.chkShowBreadcrumbs=true;
// REORDER breadcrumbs when visiting previously viewed tiddler (default is to TRIM breadcrumbs)
if (config.options.chkReorderBreadcrumbs==undefined)
config.options.chkReorderBreadcrumbs=false;
// create default breadcrumbs display as needed (default is to CREATE)
if (config.options.chkCreateDefaultBreadcrumbs==undefined)
config.options.chkCreateDefaultBreadcrumbs=true;
// show breadcrumbs for 'startup' tiddlers (default is FALSE = only show crumbs for tiddlers opened after startup)
if (config.options.chkShowStartupBreadcrumbs==undefined)
config.options.chkShowStartupBreadcrumbs=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) { // ELS: changed from passing event, "e", to passing tiddler 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
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
// 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) {
createTiddlyButton(here,"Home",null,this.home,"tiddlyLink tiddlyLinkExisting");
for (c=0; c<this.crumbs.length; c++)
if (!store.tiddlerExists(this.crumbs[c].replace(/\[\[/,'').replace(/\]\]/,'')))
this.crumbs.splice(c,1); // remove non-existing tiddler from crumbs
var homeSep=here.getAttribute("homeSep"); if (!homeSep) homeSep=this.homeSeparator;
var crumbSep=here.getAttribute("crumbSep"); if (!crumbSep) crumbSep=this.crumbSeparator;
wikify(homeSep+this.crumbs.join(crumbSep),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;
}
};
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].replace(/\[\[/,'').replace(/\]\]/,'');
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].replace(/\[\[/,'').replace(/\]\]/,'');
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,title,template,animate,slowly)
{
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|BreadcrumbsPluginInfo|
|Author|Eric Shulman|
|Source|http://www.TiddlyTools.com/#BreadcrumbsPlugin|
|Documentation|http://www.TiddlyTools.com/#BreadcrumbsPluginInfo|
|Version|1.8.2|
|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.removeTiddler|
|Description|Documentation for BreadcrumbsPlugin|
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).
!!!!!Usage/Examples
<<<
syntax:
{{{
<<breadcrumbs homeSeparator crumbSeparator>>
}}}
examples:
{{{
<<breadcrumbs>>
}}}
<<breadcrumbs>>
{{{
<<breadcrumbs "<br>" "<br>">>
}}}
<<breadcrumbs "<br>" "<br>">>
<<<
!!!!!Configuration
<<<
__''display placement:''__
<<option chkCreateDefaultBreadcrumbs>> automatically create breadcrumbs display (if needed)
>By default, the plugin automatically creates the "breadCrumbs" display element at the top of the story column, just above the tiddlerDisplay area. To manually control the display and placement of the breadcrumbs display, you can define a DIV with class="breadCrumbs" in a custom [[PageTemplate]] or embed the {{{<<breadcrumbs>>}}} macro in specific tiddler content.
>
>For example, to add the breadcrumbs below the mainMenu, change this:
{{{
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
}}}
>to:
{{{
<div id='mainMenu'>
<div refresh='content' tiddler='MainMenu'></div>
<div id='breadCrumbs' class='breadCrumbs'></div>
</div>
}}}
>You can also block automatic creation of the breadcrumbs display by setting
{{{
config.options.chkCreateDefaultBreadcrumbs=false;
}}}
>in a [[CookieJar]]/[[ConfigTweaks]] plugin tiddler.
__''separators:''__
By default, the breadcrumbs are displayed as a continuous, //horizontal// word-wrapped line of text, using pre-defined character sequences for ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > "). The //optional// ''homeSeparator'' and ''crumbSeparator'' macro parameters allow you to specify alternative separators. You can also redefine the //default// ''homeSeparator'' (" | ") and ''crumbSeparator'' (" > ") values to suit your preference. For example, to display the breadcrumbs //vertically// (in a stack, rather than a row), set the separator values to use newlines by placing some simple code into a [[CookieJar]] or [[ConfigTweaks]] plugin tiddler (tagged with systemConfig, of course):
{{{
if (!config.macros.breadcrumbs) config.macros.breadcrumbs={};
config.macros.breadcrumbs.homeSeparator="\n";
config.macros.breadcrumbs.crumbSeparator="\n";
}}}
__''other settings:''__
<<option chkShowBreadcrumbs>> show/hide breadcrumbs display
>This checkbox toggles the visibility of the breadcrumbs display. However, the display is not updated until the next crumb is added (or a previous crumb is clicked on). For immediate effect, the [[ToggleBreadcrumbs]] script uses [[InlineJavascriptPlugin]] to synchronize the checkbox setting and the breadcrumbs display.
<<option chkReorderBreadcrumbs>> re-order breadcrumbs when visiting a previously viewed tiddler
>The breadcrumbs list is ''trimmed'' when visiting a previously viewed tiddler, so that all crumbs following that tiddler are removed from the list. With ''re-ordering'' enabled, the title of the most-recently displayed tiddler is simply moved to the end of the list and individual breadcrumbs are not removed from the list unless the underlying tiddler is deleted.
<<option chkShowStartupBreadcrumbs>> show breadcrumbs for 'startup' tiddlers
>Breadcrumbs are usually only added for tiddlers that are opened after the document has been loaded, and not for tiddlers displayed during initial startup (e.g., [[DefaultTiddlers]]). Enabling this option displays breadcrumbs for all viewed tiddlers, regardless of when they are opened.
<<<
!!!!!Revisions
<<<
2007.12.04 [*.*.*] update for TW2.3.0: replaced deprecated core functions, regexps, and macros
2007.10.26 [1.8.2] documentation cleanup
2007.10.18 [1.8.1] in GetAreas(), use try/catch to avoid "Bad NPObject as private data" fatal error caused when embedded QuickTime player element is accessed by hasClass() function.
2007.10.02 [1.8.0] major documentation and code cleanup. Moved config.breadCrumbs.* to config.macros.breadcrumbs.* to consolidate objects. Also, fixed homeSeparator and crumbSeparator default handling.
2007.10.02 [1.7.0] added config.options.chkShowStartupBreadcrumbs option
2007.09.16 [1.6.1] in getAreas(), removed errant use of 'place' (was causing fatal error when creating default breadcrumbs display element). Also, added chkCreateDefaultBreadcrumbs configuration setting to enable/disable automatic creation of a default breadcrumbs display.
2007.09.16 [1.6.0] re-wrote refresh() to enable multiple display instances, by finding elements with "breadCrumbs" classname. Fallback to fixed ID (="breadCrumbs") is still used for backward-compatibility. move rendering code from refresh() to separate render() function, and added definition for {{{<<breadCrumbs>>}}} macro to support embedding breadcrumbs displays in tiddler content.
2007.09.15 [1.5.9.1] updated documentation
2007.09.15 [1.5.9] defined homeSeparator (" | ") and crumbSeparator (" > ") as object properties so that they can be redefined as desired for different layouts (e.g., using 'newline' for the crumbSeparator will arrange crumbs in a column rather than a row.
2007.06.21 [1.5.8.1] in home(), return false to prevent IE from attempting to navigate away...
2007.05.26 [1.5.8] added support for {{{<<option chkReorderBreadcrumbs>>}}} to toggle trim vs. re-order behavior when visiting previously viewed tiddlers
2007.05.25 [1.5.7] added support for {{{<<option chkShowBreadcrumbs>>}}} to toggle //display// of breadcrumbs
2007.05.24 [1.5.6] in refresh(), remove non-existing tiddler titles from crumb list. Also, hijack removeTiddler() so crumbs can be updated after tiddler is deleted.
2007.04.11 [1.5.5] added optional params to previousTiddler macro handler() to allow alternative label and tooltip text (instead of default "back")
2007.03.02 [1.5.4] in refresh(), for TW2.2, look for "storyDisplay" instead of "tiddlerDisplay" but keep fallback to "tiddlerDisplay" for TW2.1 or earlier
2007.02.24 [1.5.3] changed from hijack of onClickTiddlerLink to hijack of displayTiddler() so that ALL displayed tiddlers are recorded in the crumbs, including programmatically displayed tiddlers opened by macros, scripts, etc., (such as [[GotoPlugin]], among many others) in addition to those opened by clicks on links.
2007.02.24 [1.5.2.0] eliminated global space clutter by moving function and data declarations so they are contained inside config.breadCrumbs object.
2007.02.06 [1.5.1] added "previousTiddler" macro (for use in sidebar)
2007.02.05 [1.5.0] added "previousTiddler" toolbar command (aka, "back")
2006.08.04 [1.4.0.1] change spaces to tabs
2006.08.04 [1.4.0] modified from 1.4.0 distro: in refresh(), set {{{display:none/block}}} instead of {{{visibility:hidden/visible}}}. In home(), check for valid crumbArea before setting style.
2006.08.02 [1.4.0] Fixed bug, the redefined onClickTiddlerLink_orig_breadCrumbs works incorrectly on IE
2006.07.20 [1.3.0] Runs compatibly with TW 2.1.0 (rev #403+)
2006.02.07 [1.2.0] change global array breadCrumbs to config.breadCrumbs by Eric's suggestion
2006.02.04 [1.1.0] JSLint checked
2006.02.01 [1.0.0] initial release
<<<
<html>
<object width="400" height="400">
<param name="showcontrols" value="1">
<param name="autostart" value="0">
<embed src="./pubs/vanlaerhoven07brushup/vanlaerhoven07brushup.mov" scale="0.6" width="400" height="400" autostart="0" showcontrols="1"></embed>
</html>
|[img[./pubs/vanlaerhoven07brushup/images/teaser_bidir1.png]]|[img[./pubs/vanlaerhoven07brushup/images/teaser_bidir2.png]]|
|[img[./pubs/vanlaerhoven07brushup/images/teaser_bidir3.png]]|[img[./pubs/vanlaerhoven07brushup/images/teaser_flat1.png]]|
|[img[./pubs/vanlaerhoven07brushup/images/teaser_flat2.png]]|[img[./pubs/vanlaerhoven07brushup/images/teaser_round2.png]]|
|[img[./pubs/vanlaerhoven07brushup/images/teaser_sponge.png]]||
| borderless |k
|>|!Business card(s)|
|<html><img src="./images/card_new.jpg" style="width: 340px; "/></html>|vertical-align:top;<html><img src="./images/card_old.jpg" style="width: 250px; "/></html>|
|~|vertical-align:top;<html><img src="./images/arrow_left.jpg" style="width: 16px; "/></html>New! (<html><img src="./images/arrow_up.jpg" style="width: 16px; "/></html>Old)|
|!Mail|!Instant messaging|!Misc|
|tom.vanlaerhoven<html><img src="./images/at.jpg" style="width: 12px; "/></html>uhasselt.be|[img[./images/msn.jpg]]msn: pakewak<html><img src="./images/at.jpg" style="width: 12px; "/></html>hotmail.com|[img[./images/linkedin.jpg]] [[LinkedIn|http://www.linkedin.com/profile?viewProfile=&key=6882634]] |
|tom.vanlaerhoven<html><img src="./images/at.jpg" style="width: 12px; "/></html>gmail.com|<html><img src="./images/jabber.jpg" style="width: 12px; "/></html>jabber: pakewak<html><img src="./images/at.jpg" style="width: 12px; "/></html>amessage.be| ~PGP-key: [[tvanlaerhoven_publ.asc|./site-files/tvanlaerhoven_publ.asc]]|
/***
|Name|CoreTweaks|
|Source|http://www.TiddlyTools.com/#CoreTweaks|
|Version|n/a|
|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.4|
|Type|plugin|
|Requires||
|Overrides|various|
|Description|a small collection of overrides to TW core functions|
This tiddler contains some quick tweaks and modifications to TW core functions to provide minor changes in standard features or behavior. It is hoped that some of these tweaks may be incorporated into later versions of 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 the current version of TiddlyWiki (<<version>>). Please view [[CoreTweaksArchive]] for tweaks and modifications that may be used with earlier versions of TiddlyWiki.''
To install //all// of these tweaks, import (or copy/paste) this tiddler into your document. To include only //some// of the tweaks, you can edit the imported tiddler to remove the tweaks that you don't want. Alternatively, you could copy/paste a few selected tweaks from this tiddler into a tiddler that you create in your own document. Be certain to tag that tiddler with<<tag systemConfig>> (i.e., a plugin tiddler) and then save-and-reload for the tweaks to take effect.
***/
// // {{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;
};
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/42 - patch submitted for release in TW2.3.1
// //
// // This tweak adjusts the left position of a TW popup so that it won't overlap with the browser window's vertical scrollbar, when present.
//{{{
Popup.place = function(root,popup,offset)
{
if(!offset) var offset = {x:0, y:0};
var rootLeft = findPosX(root);
var rootTop = findPosY(root);
var rootHeight = root.offsetHeight;
var popupLeft = rootLeft + offset.x;
var popupTop = rootTop + rootHeight + offset.y;
var winWidth = findWindowWidth();
if(popup.offsetWidth > winWidth*0.75)
popup.style.width = winWidth*0.75 + "px";
var popupWidth = popup.offsetWidth;
// ELS: leave space for vertical scrollbar
var scrollWidth=winWidth-document.body.offsetWidth;
if(popupLeft+popupWidth > winWidth-scrollWidth-1)
popupLeft = winWidth-popupWidth-scrollWidth-1;
popup.style.left = popupLeft + "px";
popup.style.top = popupTop + "px";
popup.style.display = "block";
};
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/470 - OPEN
// //
// // This tweak lets you set an alternative initial focus field when editing a tiddler (default field is "text")
// // Enter initial focus field name: <<option txtEditorFocus>> (//usage:// {{{<<option txtEditorFocus>>}}})
//{{{
config.commands.editTiddler.coreTweaks_handler = config.commands.editTiddler.handler;
config.commands.editTiddler.handler = function(event,src,title)
{
if (config.options.txtEditorFocus==undefined) config.options.txtEditorFocus="text";
this.coreTweaks_handler.apply(this,arguments);
story.focusTiddler(title,config.options.txtEditorFocus);
return false;
};
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/444 - OPEN
// //
// // When invoking a macro, this tweak makes the current containing tiddler object and DOM rendering location available as a global variables (window.tiddler and window.place, respectively). These globals can then be used within "computed macro parameters" to retrieve tiddler-relative and/or DOM-relative values or perform tiddler-specific side-effect functionality.
//{{{
window.coreTweaks_invokeMacro = window.invokeMacro;
window.invokeMacro = function(place,macro,params,wikifier,tiddler) {
var here=story.findContainingTiddler(place);
window.tiddler=here?store.getTiddler(here.getAttribute("tiddler")):null;
window.place=place;
window.coreTweaks_invokeMacro.apply(this,arguments);
}
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/401 - OPEN
// //
// // This tweak allows definition of an optional [[PageTitle]] 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)
//{{{
window.coreTweaks_getPageTitle=window.getPageTitle;
window.getPageTitle=function() {
var txt=wikifyPlain("PageTitle"); if (txt.length) return txt;
return window.coreTweaks_getPageTitle.apply(this,arguments);
}
store.addNotification("PageTitle",refreshPageTitle); // so title stays in sync with tiddler changes
//}}}
// // }}}
// // {{groupbox small{
// // http://trac.tiddlywiki.org/ticket/468 - patch submitted for release in TW2.3.1
// //
// // This tweak extends the core's {{{<<tag>>}}} macro to accept additional parameters for specifying alternative label and tooltip text for the tag popup "button" link (i.e., "`PrettyTags"). Based on a suggestion by ~PBee.
//{{{
// hijack tag handler()
config.macros.tag.CoreTweaks_handler=config.macros.tag.handler;
config.macros.tag.handler = function(place,macroName,params)
{
this.CoreTweaks_handler.apply(this,arguments);
var btn=place.lastChild;
if (params[1]) btn.innerHTML=params[1];
if (params[2]) btn.title=params[2];
}
//}}}
// // }}}
// // {{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. Note: by default, this tweak only adds the "creator" field to newly created tiddlers. However, if you edit an existing tiddler that doesn't have a creator field defined, you can still force this tweak to add the missing "creator" field by enabling the following configuration checkbox:
// //
// // ''<<option chkForceCreatorField>> add missing "creator" fields when editing existing tiddlers''
// // //usage:// {{{<<option chkForceCreatorField>>}}}
//{{{
// hijack saveTiddler()
if (config.options.chkForceCreatorField==undefined) config.options.chkForceCreatorField=false;
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 || (config.options.chkForceCreatorField && !store.getValue(title,"creator")))
store.setValue(title,"creator",config.options.txtUserName);
return tiddler; // ELS 12/21/07
}
//}}}
// // }}}
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/458 - patch submitted for release in TW2.3.1
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("[["+title+"]]");
return link;
}
//}}}
// // }}}
// // {{groupbox small{
/***
http://trac.tiddlywiki.org/ticket/67 - OPEN
missing links list includes items contained within "quoted" text (i.e., content that will not render as wiki-syntax, and so CANNOT create any tiddler links, even if the quoted text matches valid link syntax)
FIX: remove content contained between certain delimiters before scanning tiddler source for possible links.
Delimiters include:
{{{
/%...%/
{{{...}}}
"""..."""
<nowiki>...</nowiki>
<html>...</html>
<script>...</script>
}}}
***/
//{{{
Tiddler.prototype.coreTweaks_changed = Tiddler.prototype.changed;
Tiddler.prototype.changed = function()
{
var savedtext=this.text;
// remove 'quoted' text before scanning tiddler source
this.text=this.text.replace(/\/%((?:.|\n)*?)%\//g,""); // /%...%/
this.text=this.text.replace(/\{{3}((?:.|\n)*?)\}{3}/g,""); // {{{...}}}
this.text=this.text.replace(/"{3}((?:.|\n)*?)"{3}/g,""); // """..."""
this.text=this.text.replace(/\<nowiki\>((?:.|\n)*?)\<\/nowiki\>/g,""); // <nowiki>...</nowiki>
this.text=this.text.replace(/\<html\>((?:.|\n)*?)\<\/html\>/g,""); // <html>...</html>
this.text=this.text.replace(/\<script((?:.|\n)*?)\<\/script\>/g,""); // <script>...</script>
this.coreTweaks_changed.apply(this,arguments);
// restore quoted text to tiddler source
this.text=savedtext;
};
//}}}
// // }}}
// // {{groupbox small{
// // This tweak adds URL paramifier handlers for "hide:elementID" and "show:elementID". This is useful for forcing the display state of specific TW page elements, without requiring StyleSheet changes. For example, if your customized StyleSheet hides the sidebar (useful for 'read only' published documents), you can force it to display when you need to edit the document by adding {{{#show:sidebar}}} to the document URL. Alternatively, you might want to supress non-tiddler content when printing by hiding the sidebars and header (e.g., {{{#hide:mainMenu hide:sidebar hide:header}}})
//{{{
if (config.paramifiers) { // check for backward-compatibility
config.paramifiers.hide = { onstart: function(id) { var e=document.getElementById(id); if (e) e.style.display="none"; } };
config.paramifiers.show = { onstart: function(id) { var e=document.getElementById(id); if (e) e.style.display="block"; } };
}
//}}}
// // }}}
// // {{groupbox small{
// // This HIJACK 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.). Based on a suggestion from Sitaram Chamarty.
//{{{
window.coreWikify = wikify;
window.wikify = function(source,output,highlightRegExp,tiddler)
{
if (source) arguments[0]=source.replace(/\\\\\n/mg,"<br>");
coreWikify.apply(this,arguments);
}
//}}}
// // }}}
[[2008 - 2009]]
[[2007 - 2008]]
[[2006 - 2007]]
[[2005 - 2006]]
[[2004 - 2005]]
[[2003 - 2004]]
[[2002 - 2003]]
[[2001 - 2002]]
/***
|''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);
};
}
//}}}
<<writePub
'vandoren08dipit'
'Peter Vandoren, Tom Van Laerhoven, Luc Claesen, Johannes Taelman, Fabian Di Fiore, Frank Van Reeth'
'~DIP-IT: Digital Infrared Painting on an Interactive Table'
'CHI 2008 Extended Abstracts, ACM, pages -, 2008'>>
|[img[./pubs/vandoren08dipit/images/chi1.png]]|[img[./pubs/vandoren08dipit/images/chi2.png]]|
/***
|''Name:''|DeprecatedFunctionsPlugin|
|''Description:''|Support for deprecated functions removed from core|
***/
//{{{
if(!version.extensions.DeprecatedFunctionsPlugin) {
version.extensions.DeprecatedFunctionsPlugin = {installed:true};
//--
//-- Deprecated code
//--
// @Deprecated: Use createElementAndWikify and this.termRegExp instead
config.formatterHelpers.charFormatHelper = function(w)
{
w.subWikify(createTiddlyElement(w.output,this.element),this.terminator);
};
// @Deprecated: Use enclosedTextHelper and this.lookaheadRegExp instead
config.formatterHelpers.monospacedByLineHelper = function(w)
{
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source);
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var text = lookaheadMatch[1];
if(config.browser.isIE)
text = text.replace(/\n/g,"\r");
createTiddlyElement(w.output,"pre",null,null,text);
w.nextMatch = lookaheadRegExp.lastIndex;
}
};
// @Deprecated: Use <br> or <br /> instead of <<br>>
config.macros.br = {};
config.macros.br.handler = function(place)
{
createTiddlyElement(place,"br");
};
// Find an entry in an array. Returns the array index or null
// @Deprecated: Use indexOf instead
Array.prototype.find = function(item)
{
var i = this.indexOf(item);
return i == -1 ? null : i;
};
// Load a tiddler from an HTML DIV. The caller should make sure to later call Tiddler.changed()
// @Deprecated: Use store.getLoader().internalizeTiddler instead
Tiddler.prototype.loadFromDiv = function(divRef,title)
{
return store.getLoader().internalizeTiddler(store,this,title,divRef);
};
// Format the text for storage in an HTML DIV
// @Deprecated Use store.getSaver().externalizeTiddler instead.
Tiddler.prototype.saveToDiv = function()
{
return store.getSaver().externalizeTiddler(store,this);
};
// @Deprecated: Use store.allTiddlersAsHtml() instead
function allTiddlersAsHtml()
{
return store.allTiddlersAsHtml();
}
// @Deprecated: Use refreshPageTemplate instead
function applyPageTemplate(title)
{
refreshPageTemplate(title);
}
// @Deprecated: Use story.displayTiddlers instead
function displayTiddlers(srcElement,titles,template,unused1,unused2,animate,unused3)
{
story.displayTiddlers(srcElement,titles,template,animate);
}
// @Deprecated: Use story.displayTiddler instead
function displayTiddler(srcElement,title,template,unused1,unused2,animate,unused3)
{
story.displayTiddler(srcElement,title,template,animate);
}
// @Deprecated: Use functions on right hand side directly instead
var createTiddlerPopup = Popup.create;
var scrollToTiddlerPopup = Popup.show;
var hideTiddlerPopup = Popup.remove;
// @Deprecated: Use right hand side directly instead
var regexpBackSlashEn = new RegExp("\\\\n","mg");
var regexpBackSlash = new RegExp("\\\\","mg");
var regexpBackSlashEss = new RegExp("\\\\s","mg");
var regexpNewLine = new RegExp("\n","mg");
var regexpCarriageReturn = new RegExp("\r","mg");
}
//}}}
// // Excludes any tiddlers from timeline that have been tagged with ''excludeTimeline''
/*{{{*/
config.macros.timeline.handler = function(place,macroName,params)
{
var field = params[0] ? params[0] : "modified";
var tiddlers = store.reverseLookup("tags","excludeTimeline",false,field);
var lastDay = "";
var last = params[1] ? tiddlers.length-Math.min(tiddlers.length,parseInt(params[1])) : 0;
for(var t=tiddlers.length-1; t>=last; t--)
{
var tiddler = tiddlers[t];
var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
if(theDay != lastDay)
{
var theDateList = document.createElement("ul");
place.appendChild(theDateList);
createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
lastDay = theDay;
}
var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink");
theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
}
}
/*}}}*/
<html>
<object width="400" height="400">
<param name="showcontrols" value="1">
<param name="autostart" value="0">
<embed src="./pubs/vanhaevre07fromdust/vanhaevre07fromdust.mov" scale="0.6" width="400" height="400" autostart="0" showcontrols="1"></embed>
</html>
|[img[./pubs/vanhaevre07fromdust/images/teaser_tip.png]]|[img[./pubs/vanhaevre07fromdust/images/teaser_guy.png]]|
|[img[./pubs/vanhaevre07fromdust/images/teaser_art.png]]||
<<writePub
'vanlaerhoven08handpainted'
'Tom Van Laerhoven, Fabian Di Fiore, Frank Van Reeth'
'[[Hand-painted Animation with Intelligent Brushes]]'
'In Journal of Computer Animation and Virtual Worlds 2008; 19 (Special Issue ~CASA2008), pages 365-374, Seoul, ~North-Korea, September 2008'
'http://www.youtube.com/watch?v=LZ2UdzKLjWY'
>>
|''Abstract'' | <html><img width='190' src='./pubs/vanlaerhoven08handpainted/images/fire.gif'/></html>|
|In this paper we argue for the concept of brushes and pigments enhanced with behavioural intelligence as a complement to established 2D computer animation techniques.|~|
|Our approach allows the user to enrich and animate interactively created images by semi-autonomously embedding procedural animation into them. This way, artistic skills of trained animators become within reach of everyone in the digital world, even to completely novice users.|~|
|To exemplify this concept, we elaborate on several special-purpose brushes and animated pigment for painting with animation. These include a programmable semi-autonomous brush used to paint variations of strokes in successive frames (e.g., flames of fire), the moving-dab brush which enables dabs of paint to follow a user-defined path (e.g., smoke puffs) and animated pigment to produce secondary motion such as vibrant or waving paint textures.|~|
|We believe our system offers a new fresh perspective on 2D computer aided animation production and associated tools.|~|
|<html><img width='750' src='./pubs/vanlaerhoven08handpainted/images/water.gif'/></html>||
Link to movie (20Mb) ([[mov|./paintpal/handpaintedanimation_casa2008_high.mov]])
<html>
<object width="600" height="450">
<param name="showcontrols" value="1">
<param name="autostart" value="0">
<embed src="./paintpal/handpaintedanimation_casa2008_high.mov" scale="0.58" width="600" height="550" autostart="0" showcontrols="1"></embed>
</html>
<html><object width="425" height="350"> <param name="movie" value="http://www.youtube.com/watch?v=LZ2UdzKLjWY"> </param> <embed src="http://www.youtube.com/v/LZ2UdzKLjWY" type="application/x-shockwave-flash" width="425" height="350"> </embed> </object></html>
<<writePub
'vandoren08intupaint'
'Peter Vandoren, Tom Van Laerhoven, Johannes Taelmann, Luc Claesen, Frank Van Reeth'
'[[IntuPaint: Bridging the Gap between Physical and Digital Painting]]'
'Accepted for publication in Proceedings of IEEE Tabletop and Interactive Surfaces, 2008'
'http://www.youtube.com/watch?v=n2IW4koT7Gw'
>>
''Abstract''
This paper presents a novel interface for a digital paint system: ~IntuPaint. A tangible interface for a digital paint easel, using an interactive surface and electronic brushes with a tuft of bristles, has been developed. The flexible brush bristles conduct light by means of total internal reflection inside the individual bristles. This enables to capture subtle paint nuances of the artist in a way that was not possible in previous technologies. This approach provides natural interaction and enables detailed tracking of specific brush strokes. Additional tangible and finger-based input techniques allow for specific paint operations or effects. ~IntuPaint also offers an extensive model-based paint simulation, rendering realistic paint results. The reality-based approach in the combination of user interface and paint software is a new step forward to bridge the gap between physical and digital painting, as is demonstrated by initial user tests.
<html><object width="425" height="350"> <param name="movie" value="http://www.youtube.com/watch?v=n2IW4koT7Gw"> </param> <embed src="http://www.youtube.com/v/n2IW4koT7Gw" type="application/x-shockwave-flash" width="425" height="350"> </embed> </object></html>
<html><object width="425" height="350"> <param name="movie" value="http://www.youtube.com/watch?v=9JEn3j-jaCw"> </param> <embed src="http://www.youtube.com/v/9JEn3j-jaCw" type="application/x-shockwave-flash" width="425" height="350"> </embed> </object></html>
|[img[./pubs/vandoren08intupaint/images/intupainting_01.jpg]]|[img[./pubs/vandoren08intupaint/images/intupainting_02.jpg]]|
|[img[./pubs/vandoren08intupaint/images/intupainting_03.jpg]]|[img[./pubs/vandoren08intupaint/images/intupainting_04.jpg]]|
|[img[./pubs/vandoren08intupaint/images/intupainting_bstevens.jpg]]|[img[./pubs/vandoren08intupaint/images/intupainting_dkonings.jpg]]|
|[img[./pubs/vandoren08intupaint/images/intupainting_screenshot.jpg]]|>|
/***
|''Name:''|LegacyStrikeThroughPlugin|
|''Description:''|Support for legacy (pre 2.1) strike through formatting|
|''Version:''|1.0.2|
|''Date:''|Jul 21, 2006|
|''Source:''|http://www.tiddlywiki.com/#LegacyStrikeThroughPlugin|
|''Author:''|MartinBudden (mjbudden (at) gmail (dot) com)|
|''License:''|[[BSD open source license]]|
|''CoreVersion:''|2.1.0|
***/
//{{{
// Ensure that the LegacyStrikeThrough Plugin is only installed once.
if(!version.extensions.LegacyStrikeThroughPlugin) {
version.extensions.LegacyStrikeThroughPlugin = {installed:true};
config.formatters.push(
{
name: "legacyStrikeByChar",
match: "==",
termRegExp: /(==)/mg,
element: "strike",
handler: config.formatterHelpers.createElementAndWikify
});
} //# end of "install only once"
//}}}
!!Friendly (ex-)Colleagues
[[Kris Luyten| http://research.edm.uhasselt.be/~kris/]]
[[Fabian Di Fiore| http://research.edm.uhasselt.be/~fdifiore]]
[[Tom Mertens| http://research.edm.uhasselt.be/~tmertens/]]
[[Pieter Jorissen| http://research.edm.uhasselt.be/~pjorissen]]
[[Mark Gerrits| http://research.edm.uhasselt.be/~mgerrits]]
[[Yannick Francken| http://research.edm.uhasselt.be/~yfrancken]]
[[Peter Quax| http://research.edm.uhasselt.be/~pquax]]
[[Cedric Vanaken| http://research.edm.uhasselt.be/~cvanaken]]
[[William Van Haevre| http://research.edm.uhasselt.be/~wvanhaevre]]
[[Tom Haber| http://research.edm.uhasselt.be/~thaber]]
[[Bert De Decker| http://research.edm.uhasselt.be/~bdedecker]]
[[Erik Hubo| http://research.edm.uhasselt.be/~ehubo]]
[[Chris Hermans|http://research.edm.uhasselt.be/~chermans]]
[[Tom Cuypers|http://research.edm.uhasselt.be/~tcuypers]]
!!Misc
[[The Expertise Centre for Digital Media (EDM)|http://www.edm.uhasselt.be/]]
[[Hasselt University|http://www.uhasselt.be]]
[[Contact]]
[[Research]]
<<slider chkSliderCourses Courses 'Courses @ UHasselt Ā»' 'Teaching & Related'>>
<<slider chkSliderProjects Projects 'Projects Ā»' 'Small Projects'>>
[[Personal]]
[[Links]]
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-384023-1";
urchinTracker();
</script>
<<search>><<closeAll>><<upload>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>>
A multitouch fingerpaint application, using an interactive surface based on FTIR technology (by Johannes Taelman).
Users can pick up the thick impasto paint by smearing fingers through the splats at the bottom of the canvas. All fingers share just one reservoir, representing the paint that adheres to the hand. Paint is exchanged between canvas and finger in two directions, enabling on-canvas color mixing.
The paint layer is represented by a height field and rendered using per-pixel bumpmapping.
[[Movie|./projects/multipaint/movies/fingerpaint.mov]] (mov, 3.1Mb).
<html><object width="425" height="350"> <param name="movie" value="http://www.youtube.com/watch?v=g6YPZuEGQLU&ap=%2526fmt%3D18"> </param> <embed src="http://www.youtube.com/v/g6YPZuEGQLU&ap=%2526fmt%3D18" type="application/x-shockwave-flash" width="425" height="350"> </embed> </object></html>
@ Tentoonstelling: [[De Krook|http://dekrook.be/]]
[img[./projects/fingerpaint/images/dekrook.jpg]]
@ [[Creativity World Forum|http://www.creativityworldforum.be]]
[img[./projects/fingerpaint/images/creativityworldforum.jpg]]
!''~DIP-SHIT: Digital Infrared Painting with Fecal Excrement''
|''Abstract''|[img[./pubs/notquitepublished/images/teaser1.jpg]]|
|For thousands of years people have been fascinated by creating art with fecal excrement. Feces, pooh or doo-doo, forms a solid and easily available substance from either animal or human origin, and is perfectly suitable for creating aesthetically pleasing images. The activity of fecal art is very straightforward and suļ¬ciently accessible so that users of all ages can practice it; yet, mastering it is complex enough that it remains challenging to even an expert.|~|
|In this work we present a natural poop-grasping interface using an interactive multi-touch table based on FTIR technology. Users can collaborate in their caca-craft activities, making use of all ļ¬ngers to apply, shape and smear the bodily waste onto a large canvas. Furthermore, digital dung has the advantage that it can be comfortably conļ¬gured, determining its color, sogginess and texture by merely a touch of a button, and without the unpleasant odors. |~|
|Results show that ~DIP-SHIT is able to reproduce the real-life experience of turd-sculpting, enriched with all advantages of the digital world. <html><a href='./pubs/notquitepublished/dip-shit_abstract.pdf'><img src='./images/pdficon.png'/></html>|~|
!''~DIP-SHIT Poster''
[img[./pubs/notquitepublished/images/dip-shit_poster.png]]
Last Updated: 08/02/03
<<writeBelStats>> Copyright Ā© 2008
A Kdevelop 3.1 Qmake-based ~OpenGL application template for kdevappwizard.
Put this template in your Kdevelop wizard to create simple painless ~OpenGL applications. Picking code already added.
* [[template_qmakeopengl_v001.tar.gz|./projects/template_qmakeopengl_v001.tar.gz]] (15-08-03)
An implementation of a distributed cellular automaton ("game of life") using [[PVM|http://www.csm.ornl.gov/pvm/]]. It is very useless, except for testing a crowd-computation model.
* [[pvm_automaton_v001.tar.gz | ./projects/pvm_automaton_v001.tar.gz]] (18-08-03)
An implementation of a parallel merge sort algorithm using [[PVM|http://www.csm.ornl.gov/pvm/]]. It is very useless, except for testing a tree-computation model.
* [[pvm_mergesort_v001.tar.gz| ./projects/pvm_mergesort_v001.tar.gz]] (20-06-03)
<!--{{{-->
<div id='header' class='header'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu'>
<span refresh='content' tiddler='MainMenu'></span>
<span id='noticeBoard' refresh='content' tiddler='NoticeBoard'></span>
</div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='MochaSideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--<div id='contentFooter' refresh='content' tiddler='contentFooter'></div>-->
<!--}}}-->
PasswordOptionPlugin extends the core Options with a non encrypted password type.
Notice:
*How a style can be specified for a specific option in StyleSheet
----
Test Password: <<option pasPassword myPasOptionInput >>
/***
|''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"
});
*/
//}}}
!!Travel Footprint
<html>
<img src="http://www.world66.com/myworld66/visitedCountries/worldmap?visited=USBRATBECZFRDEGRITLUNLSKCHUKVACNMYKRAU"><br/>
<a href="http://www.world66.com/myworld66">create your own visited country map</a>
</html>
!!Hard & Software
--Dell Inspiron 8500-- ~MacBook with --[[Gentoo|http://www.gentoo.org/]] Linux-- [[Mac OS X Leopard|http://www.apple.com/macosx/]].
!!Music
<html>
<a target="_blank" href="http://hypem.com/Pakewak?w=1" title="Hype Machine - Music Widget MP3 Blogs"><img border="0" alt="Hype Machine Music Widget MP3 Blogs" src="http://hypem.com/widget/v2/loved/Pakewak/10/hype.png%3Fbcol=FEF2EB&tcol=111111&lcol=F26A21" /></a>
</html>
[[Multitouch Fingerpaint]]
[[TaskBarTetris]]
[[XGL DTD]]
[[2D Navier-Stokes]]
[[distccWebView]]
[[PVM cellular automaton]]
[[PVM merge sort]]
[[Short introduction to PHP]]
[[OpenGL app template]]
[[Not quite published]]
/***
|''Name''|PubWriterPlugin|
|''Version''|0.1|
|''Author''|Tom Van Laerhoven|
|''Source''|[[Tom Van Laerhoven's page|http://research.uhasselt.be/tvanlaerhoven/#PubWriterPlugin]]|
|''License''|none|
|''~CoreVersion''|2.1|
|''Type''|macro|
|''Requires''|N/A|
|''Overrides''|N/A|
|''Description''|Formats and displays publication entries.|
!Notes
Made for own purposes.
!Usage
{{{
<<writePub pubId authors title trailing>>
}}}
!!Example
!Revision History
!!v0.1 (2008-02-02)
* initial release
!Code
***/
//{{{
config.macros.writePub = {
handler: function (place, macroName, params, wikifier, paramString, tiddler)
{
var pubCounter;
var contents;
var offset = 0;
var pubId = params[offset];
var authors = params[offset+1];
var title = params[offset+2];
var trailing = params[offset+3];
var youtubeurl = params[offset+4];
var contents = this.format(pubId, authors, title, trailing, youtubeurl);
wikify(contents, place);
},
format: function(pubId, authors, title, trailing, youtubeurl)
{
var thumbCode = '[img[' + './pubs/' + pubId +'/thumb.png' + ']]';
var authorCode = authors;
var titleCode = "''\"" + title + "\"''";
var trailingCode = trailing;
var pdfCode = '<html><a href=\"pubs/' + pubId + '/' + pubId + '.pdf\"><img border=\"0\" src=\"./images/pdficon.png\" alt=\"PDF\"/></a></html>';
var youTubeCode = '';
if (youtubeurl)
youTubeCode = ' <html><a href=\"' + youtubeurl + '\"><img border=\"0\" src=\"./images/youtube.png\" alt=\"YOUTUBE\"/></a></html>';
var contents = '|' + thumbCode + '|' + authorCode + ', ' + titleCode + ', ' + trailingCode + '. ' + pdfCode + youTubeCode + '|';
return contents;
}
};
//}}}
!Publications & Related
!!2010
<<writePub
'claesen10videoprocessing'
'Luc Claesen, Peter Vandoren, Tom Van Laerhoven, Andy Motten, Domien Nowicki, Frank Van Reeth, Eddy Flerackers'
'[[Video Processing SoC for Low-Latency Real-Time Interactive Real-Brush Painting System]]'
'Accepted for publication in Proceedings of the 18th Conference on VLSI Design/CAD, 2010'
>>
!!2009
<<writePub
'vandoren09fluidpaint'
'Peter Vandoren, Luc Claesen, Tom Van Laerhoven, Johannes Taelman, Frank Van Reeth'
'[[FluidPaint: an Interactive Digital Painting System using Real Wet Brushes]]'
'Accepted for publication in Proceedings of IEEE Tabletop and Interactive Surfaces, 2009'
'http://www.youtube.com/watch?v=fkl782OqqmA'
>>
!!2008
<<writePub
'vandoren08intupaint'
'Peter Vandoren, Tom Van Laerhoven, Johannes Taelman, Luc Claesen, Frank Van Reeth'
'[[IntuPaint: Bridging the Gap between Physical and Digital Painting]]'
'In Proceedings of IEEE Tabletop and Interactive Surfaces, 2008'
'http://www.youtube.com/watch?v=n2IW4koT7Gw'
>><<writePub
'vanlaerhoven08handpainted'
'Tom Van Laerhoven, Fabian Di Fiore, Frank Van Reeth'
'[[Hand-painted Animation with Intelligent Brushes]]'
'In Journal of Computer Animation and Virtual Worlds 2008; 19 (Special Issue ~CASA2008), pages 365-374, Seoul, ~North-Korea, September 2008'
'http://www.youtube.com/watch?v=LZ2UdzKLjWY'
>><<writePub
'vandoren08dipit'
'Peter Vandoren, Tom Van Laerhoven, Luc Claesen, Johannes Taelman, Fabian Di Fiore, Frank Van Reeth'
'DIP-IT: Digital Infrared Painting on an Interactive Table'
'CHI 2008 Extended Abstracts, ACM, pages -, 2008'>>
!!2007
<<writePub
'vanlaerhoven07brushup'
'Tom Van Laerhoven, Frank Van Reeth'
'[[Brush Up Your Painting Skills]]: Realistic Brush Design for Interactive Painting Applications'
'Computer Graphics International (~CGI2007), The Visual Computer, pages 763-771, 2007'
'http://www.youtube.com/watch?v=W4suJCMdnsU'
>><<writePub
'vanhaevre07fromdust'
'William Van Haevre, Tom Van Laerhoven, Fabian Di Fiore, Frank Van Reeth'
'[[From Dust till Drawn]]: A Real-time Bidirectional Pastel Simulation'
'Computer Graphics International (~CGI2007), The Visual Computer, pages 925-934, 2007'
'http://www.youtube.com/watch?v=CNfAXjRQkr0'>>
!!2006
<<writePub
'vanlaerhoven06using'
'Tom Van Laerhoven, Geert Vanderhulst, Kris Luyten, Frank Van Reeth, Karin Coninx'
'Using Device Federations to Enhance the Creative Process in a Distributed Interaction Environment'
'Technical Reports ~TR-UH-EDM-0603, EDM/UH, Diepenbeek, Belgium, 2006'
>><<writePub
'vanlaerhoven06phd'
'Tom Van Laerhoven'
'An Extensible Simulation Framework Supporting Physically-based Interactive Painting'
'~PhD, transnational University Limburg, 21 juni 2006'
>><<writePub
'vanlaerhoven06proposition'
'Tom Van Laerhoven'
'Usage of Device Federations can Enhance the Creative Process in a Distributed Interaction Environment'
'Proposition, transnational University Limburg, 21 juni 2006'
>><<writePub
'beets06introducing'
'Koen Beets, Tom Van Laerhoven, Frank Van Reeth'
'Introducing Artistic Tools in an Interactive Paint System'
"In Proceedings of WSCG'2006, Volume 14, pages 27-54, Pilzen, SK, January 2006">>
!!2005
<<writePub
'vanlaerhoven05introducing'
'Tom Van Laerhoven, Koen Beets, Frank Van Reeth'
'Introducing Artistic Tools in an Interactive Paint System'
'Technical Report ~TR-UH-EDM-0501, EDM/UH, Diepenbeek, Belgium, 2005'
>><<writePub
'vanlaerhoven05realtime'
'Tom Van Laerhoven, Frank Van Reeth'
'Real-time Simulation of Watery Paint'
'In Journal of Computer Animation and Virtual Worlds, 16:3-4 (Special Issue ~CASA2005), pages 429-439, ~Hong-Kong, China, October 2005'
>><<writePub
'vanlaerhoven05thinpaint'
'Tom Van Laerhoven, Frank Van Reeth'
'Real-time Simulation of Thin Paint Media'
'In Conference Abstracts and Applications of ACM SIGGRAPH 2005, Los Angeles, July 31-Aug 2, 2005'>>
!!2004
<<writePub
'vanlaerhoven04papermodel'
'Tom Van Laerhoven, Jori Liesenborgs, Frank Van Reeth'
'A Paper Model for Real-time Watercolor Simulation'
'Technical Report ~TR-LUC-EDM-0403, EDM/LUC, Diepenbeek, Belgium, 2004'
>><<writePub
'vanlaerhoven04realtime'
'Tom Van Laerhoven, Jori Liesenborgs, Frank Van Reeth'
'Real-time Watercolor Painting on a Distributed Paper Model'
'In Proceedings of the Computer Graphics International Conference 2004, pages 640-643, Crete, Greece, June 16-19 2004'>>
!!2003
<<writePub
'vanlaerhoven03generalized'
'Tom Van Laerhoven, Chris Raymaekers, Frank Van Reeth'
'Generalized Object Interactions in a ~Component-Based Simulation Environment'
'In Journal of Winter Conference on Computer Graphics, pages 472-473, Pilsen, SK, February 3-7 2003'
>> <<writePub
'luyten03runtime'
'Kris Luyten, Tom Van Laerhoven, Karin Coninx and Frank Van Reeth'
'Runtime transformations for modal independent user interface migration'
'In Interacting with Computers, pages 329-347, Elsevier Science, 2003'>>
!!2002
<<writePub
'vanlaerhoven02plab'
'Tom Van Laerhoven, Frank Van Reeth'
'The pLab Project: An Extensible Architecture for ~Physically-Based Simulations'
'In Proceedings of Spring Conference on Computer Graphics, pages 129-135, Budmerice, SL, April 24-27 2002'
>> <<writePub
'luyten02specifying'
'Kris Luyten, Tom Van Laerhoven'
'Specifying User Interfaces for Runtime Modal Independent Migration'
"In Proceedings of CADUI'2002 International Conference on ~Computer-Aided Design of User Interfaces, pages 238-295, Valenciennes, FR, May 15-17 2002">>
!!2000
Tom Van Laerhoven "Physically Based Modelling - Rigid Body Dynamics", Master thesis, transnational University Limburg, 1999-2000.
[img[./sante/foxy_intense.gif]]
<html>
<a href='./sante/bbq_v2.jpg'><img width='640' src='./sante/bbq_v2.jpg' /></a>
</html>
<html><embed src='./sante/foxy_watercolor.mov' loop='true' autostart='true' width='480' height='400'/></html>
A 10-page dutch introduction to PHP ([[.pdf|./projects/phpintro_2001.pdf]]) (03-02-01)
<<search>><<upload>><<closeAll>><<permaview>><<toolbar permalink>><<newTiddler>><<newJournal "DD MMM YYYY" "journal">><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel "options Ā»" "Change TiddlyWiki advanced options">>
/***
|Name|SinglePageModePlugin|
|Source|http://www.TiddlyTools.com/#SinglePageModePlugin|
|Documentation|http://www.TiddlyTools.com/#SinglePageModePluginInfo|
|Version|2.8.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|Story.prototype.displayTiddler(), Story.prototype.displayTiddlers()|
|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 chkSinglePageKeepFoldedTiddlers>> Don't auto-close folded tiddlers
><<option chkSinglePagePermalink>> Automatically permalink current tiddler
<<option chkTopOfPageMode>> Always open tiddlers at the top of the page
<<option chkBottomOfPageMode>> Always 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.03.14 [2.8.2] in displayTiddler(), if editing specified tiddler, just move it to top/bottom of story *without* re-rendering (prevents discard of partial edits).
| 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.SinglePageMode= {major: 2, minor: 8, revision: 2, date: new Date(2008,3,14)};
//}}}
//{{{
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.chkSinglePageKeepFoldedTiddlers==undefined) config.options.chkSinglePageKeepFoldedTiddlers=true;
if (config.options.chkSinglePagePermalink==undefined) config.options.chkSinglePagePermalink=true;
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=true;
if (config.optionsDesc) {
config.optionsDesc.chkSinglePageMode="Display one tiddler at a time";
config.optionsDesc.chkSinglePageKeepFoldedTiddlers="Don't auto-close folded tiddlers";
config.optionsDesc.chkSinglePagePermalink="Automatically permalink current tiddler";
config.optionsDesc.chkSinglePageAutoScroll="Automatically scroll tiddler into view (if needed)";
config.optionsDesc.chkTopOfPageMode="Always open tiddlers at the top of the page";
config.optionsDesc.chkBottomOfPageMode="Always open tiddlers at the bottom of the page";
} else {
config.shadowTiddlers.AdvancedOptions += "\
\n<<option chkSinglePageMode>> Display one tiddler at a time \
\n<<option chkSinglePageKeepFoldedTiddlers>> Don't auto-close folded tiddlers \
\n<<option chkSinglePagePermalink>> Automatically permalink current tiddler \
\n<<option chkSinglePageAutoScroll>> Automatically scroll tiddler into view (if needed) \
\n<<option chkTopOfPageMode>> Always open tiddlers at the top of the page \
\n<<option chkBottomOfPageMode>> Always open tiddlers at the bottom of the page";
}
//}}}
//{{{
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=convertUTF8ToUnicode(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,title,template,animate,slowly)
{
var opt=config.options;
if (opt.chkSinglePageMode) {
// close all tiddlers except current tiddler, tiddlers being edited, and tiddlers that are folded (optional)
story.forEachTiddler(function(tid,elem) {
if ( tid==title
|| elem.getAttribute("dirty")=="true"
|| (opt.chkSinglePageKeepFoldedTiddlers && elem.getAttribute("folded")=="true"))
return;
story.closeTiddler(tid);
});
}
else if (opt.chkTopOfPageMode)
arguments[0]=null;
else if (opt.chkBottomOfPageMode)
arguments[0]="bottom";
if (opt.chkSinglePageMode && opt.chkSinglePagePermalink && !config.browser.isSafari) {
window.location.hash = encodeURIComponent(convertUnicodeToUTF8(String.encodeTiddlyLink(title)));
config.lastURL = window.location.hash;
document.title = wikifyPlain("SiteTitle") + " - " + title;
if (!config.SPMTimer) config.SPMTimer=window.setInterval(function() {checkLastURL();},1000);
}
var tiddlerElem=document.getElementById(story.idPrefix+title); // ==null unless tiddler is already display
if (tiddlerElem && tiddlerElem.getAttribute("dirty")=="true") { // editing... move tiddler without re-rendering
var isTopTiddler=(tiddlerElem.previousSibling==null);
if (!isTopTiddler && (opt.chkSinglePageMode || opt.chkTopOfPageMode))
tiddlerElem.parentNode.insertBefore(tiddlerElem,tiddlerElem.parentNode.firstChild);
else if (opt.chkBottomOfPageMode)
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) {
var yPos=ensureVisible(tiddlerElem); // scroll to top of tiddler
var isTopTiddler=(tiddlerElem.previousSibling==null);
if (opt.chkSinglePageMode||opt.chkTopOfPageMode||isTopTiddler)
yPos=0; // scroll to top of page instead of top of tiddler
if (opt.chkAnimate) // defer scroll until 200ms after animation completes
setTimeout("window.scrollTo(0,"+yPos+")",config.animDuration+200);
else
window.scrollTo(0,yPos); // scroll immediately
}
}
if (Story.prototype.SPM_coreDisplayTiddlers==undefined)
Story.prototype.SPM_coreDisplayTiddlers=Story.prototype.displayTiddlers;
Story.prototype.displayTiddlers = function() {
// suspend single-page mode (and/or top/bottom display options) 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;
}
//}}}
/***
|''Name:''|SparklinePlugin|
|''Description:''|Sparklines macro|
***/
//{{{
if(!version.extensions.SparklinePlugin) {
version.extensions.SparklinePlugin = {installed:true};
//--
//-- Sparklines
//--
config.macros.sparkline = {};
config.macros.sparkline.handler = function(place,macroName,params)
{
var data = [];
var min = 0;
var max = 0;
var v;
for(var t=0; t<params.length; t++) {
v = parseInt(params[t]);
if(v < min)
min = v;
if(v > max)
max = v;
data.push(v);
}
if(data.length < 1)
return;
var box = createTiddlyElement(place,"span",null,"sparkline",String.fromCharCode(160));
box.title = data.join(",");
var w = box.offsetWidth;
var h = box.offsetHeight;
box.style.paddingRight = (data.length * 2 - w) + "px";
box.style.position = "relative";
for(var d=0; d<data.length; d++) {
var tick = document.createElement("img");
tick.border = 0;
tick.className = "sparktick";
tick.style.position = "absolute";
tick.src = "data:image/gif,GIF89a%01%00%01%00%91%FF%00%FF%FF%FF%00%00%00%C0%C0%C0%00%00%00!%F9%04%01%00%00%02%00%2C%00%00%00%00%01%00%01%00%40%02%02T%01%00%3B";
tick.style.left = d*2 + "px";
tick.style.width = "2px";
v = Math.floor(((data[d] - min)/(max-min)) * h);
tick.style.top = (h-v) + "px";
tick.style.height = v + "px";
box.appendChild(tick);
}
};
}
//}}}
/*{{{*/
.breadCrumbs { margin-top: 2px; }
.breadCrumbs a {
color: #000;
font-weight: normal;
background-color: #eee;
border: 1px solid #BFB6B3;
border-bottom: 0px;
padding: 2px;
margin-bottom: 0;
}
.breadCrumbs a:hover {
background-color: #ddd;
}
/*}}}*/
/*{{{*/
/*Mocha TiddlyWiki Theme*/
/*Version 1.0*/
/*Design and CSS originally by Anthonyy, ported to TiddlyWiki by Saq Imtiaz.*/
/*}}}*/
/*{{{*/
#tiddlerDisplay {
border: 1px solid #eee;
margin-top: 0;
}
#contentWrapper {
margin: 0 3.4em;
font-family: Lucida Grande, Tahoma, Arial, Helvetica, sans-serif; /* Lucida Grande for the Macs, Tahoma for the PCs */
font-size: 11px;
line-height: 1.6em;
color: #666;
}
.header {
background: #fff;
padding-top: 10px;
clear: both;
border-bottom: 0px solid #948979;
}
.headerShadow { padding: 2.6em 0em 0.5em 0em; }
.siteTitle {
font-family: 'Trebuchet MS' sans-serif;
font-weight: bold;
font-size: 32px;
color: #CC6633;
margin-bottom: 30px;
background-color: #FFF;
}
.siteTitle a{color:#CC6633; border-bottom:1px dotted #cc6633;}
.siteSubtitle {
font-size: 1.0em;
display: block;
margin: .5em 3em; color: #999999;
}
#mainMenu {
position:relative;
float:left;
margin-bottom:0em;
display:inline;
text-align:left;
padding: 2em 0.5em 0.5em 0em;
width:13em;
font-size:1.1em;
}
#sidebar{
position:relative;
float:right;
margin-bottom:1em;
padding-top:2em;
display:inline;
}
#displayArea {
margin: 0em 17em 0em 15em;
}
.tagClear {clear:none;}
#contentFooter {background:#575352; color:#BFB6B3; clear: both; padding: 0.5em 1em;}
#contentFooter a {
color: #BFB6B3;
border-bottom: 1px dotted #BFB6B3;
}
#contentFooter a:hover {
color: #FFFFFF;
background-color:#575352;
}
a,#sidebarOptions .sliderPanel a{
color:#CC6714;
text-decoration: none;
}
a:hover,#sidebarOptions .sliderPanel a:hover {
color:#CC6714;
background-color: #F5F5F5;
}
.viewer .button, .editorFooter .button{
color: #666;
border: 1px solid #CC6714;
}
.viewer .button:hover,
.editorFooter .button:hover{
color: #fff;
background: #CC6714;
border-color: #CC6714;
}
.viewer .button:active, .viewer .highlight,.editorFooter .button:active, .editorFooter .highlight{color:#fff; background:#575352;border-color:#575352;}
#mainMenu a {
display: block;
padding: 5px;
/*border-bottom: 1px solid #CCC;*/
}
#mainMenu a:link, #navlist a:visited {
color:#CC6714;
/*color:#999999;*/
text-decoration: none;
}
#mainMenu .sliderPanel a
{
color: #999999;
margin-left: 1em;
padding: 0em;
font-size: 0.9em;
}
#mainMenu a:hover {
background: #000000 url(arrow.gif) 96% 50% no-repeat;
background-color: #F5F5F5;
color:#CC6714;
}
#mainMenu a:hover, #mainMenu a:active, #mainMenu .highlight, #mainMenu .marked {
background: #000000 url(arrow.gif) 96% 50% no-repeat;
background-color: #F5F5F5;
color:#CC6714;
}
#mainMenu span {position:relative;}
#mainMenu br {display:none;}
#sidebarOptions a {
color:#999;
text-decoration: none;
}
#sidebarOptions a:hover {
color:#4F4B45;
background-color: #F5F5F5;border:1px solid #fff;
}
#sidebarOptions {line-height:1.4em;}
.tiddler {
padding-bottom: 40px;
border-bottom: 1px solid #DDDDDD;
}
.title {color:#CC6633;}
.subtitle, .subtitle a { color: #999999; font-size: 1.0em;margin:0.2em;}
.shadow .title{color:#948979;}
.selected .toolbar a {color:#999999;}
.selected .toolbar a:hover {color:#4F4B45; background:transparent;border:1px solid #fff;}
.toolbar .button:hover, .toolbar .highlight, .toolbar .marked, .toolbar a.button:active{color:#4F4B45; background:transparent;border:1px solid #fff;}
.listLink,#sidebarTabs .tabContents {line-height:1.5em;}
.listTitle {color:#888;}
#sidebarTabs .tabContents {background:#fff;}
#sidebarTabs .tabContents .tiddlyLink, #sidebarTabs .tabContents .button{color:#999;}
#sidebarTabs .tabContents .tiddlyLink:hover,#sidebarTabs .tabContents .button:hover{color:#4F4B45;background:#fff}
#sidebarTabs .tabContents .button:hover, #sidebarTabs .tabContents .highlight, #sidebarTabs .tabContents .marked, #sidebarTabs .tabContents a.button:active{color:#4F4B45;background:#fff}
.tabSelected{color:#fff; background:#948979;}
.tabUnselected {
background: #ccc;
}
.tabSelected, .tabSelected:hover {
color: #fff;
background: #948979;
border: solid 1px #948979;
padding-bottom:1px;
}
.tabUnselected {
color: #999;
background: #eee;
border: solid 1px #ccc;
padding-bottom:1px;
}
#sidebarTabs .tabUnselected { border-bottom: none;padding-bottom:3px;}
#sidebarTabs .tabSelected{padding-bottom:3px;}
#sidebarTabs .tabUnselected:hover { border-bottom: none;padding-bottom:3px;color:#4F4B45}
#sidebarOptions .sliderPanel {
background: #fff; border:none;
font-size: .9em;
}
#sidebarOptions .sliderPanel a {font-weight:normal;}
#sidebarOptions .sliderPanel input {border:1px solid #999;}
.viewer blockquote {
border-left: 3px solid #948979;
}
.viewer table {
border: 1px solid #fff;
}
.viewer tr,
.viewer td {
border: 1px solid #fff;
vertical-align: top;
}
.viewer table.borderless,
.viewer table.borderless * {
border-style: hidden;
}
.viewer th, thead td {
background: #DDDDDD;
border: 4px solid #fff;
color: #000;
font-weight: bold;
text-align: left;
padding: 0em 0em 0em 0.5em;
}
.viewer pre {
border: 1px solid #948979;
background: #f5f5f5;
}
.viewer code {
color: #2F2A29;
}
.viewer hr {
border-top: dashed 1px #948979;
}
.editor input {
border: 1px solid #948979;
}
.editor textarea {
border: 1px solid #948979;
}
.popup {
background: #948979;
border: 1px solid #948979;
}
.popup li.disabled {
color: #000;
}
.popup li a, .popup li a:visited {
color: #eee;
border: none;
}
.popup li a:hover {
background: #575352;
color: #fff;
border: none;
}
.tagging, .tagged {
border: 1px solid #eee;
background-color: #F7F7F7;
}
.selected .tagging, .selected .tagged {
background-color: #eee;
border: 1px solid #BFBAB3;
}
.tagging .listTitle, .tagged .listTitle {
color: #bbb;
}
.selected .tagging .listTitle, .selected .tagged .listTitle {
color: #666;
}
.tagging .button, .tagged .button {
color:#aaa;
}
.selected .tagging .button, .selected .tagged .button {
color:#4F4B45;
}
.highlight, .marked {background:transparent; color:#111; border:none; text-decoration:underline;}
.tagging .button:hover, .tagged .button:hover, .tagging .button:active, .tagged .button:active {
border: none; background:transparent; text-decoration:underline; color:#000;
}
h1,h2,h3,h4,h5 { color: #666; background: transparent; padding-bottom:2px; font-family: Arial, Helvetica, sans-serif; }
h1 {font-size:18px;}
h2 {font-size:16px;}
h3 {font-size: 14px;}
#messageArea {
border: 4px solid #948979;
background: #f5f5f5;
color: #999;
font-size:90%;
}
#messageArea a:hover { background:#f5f5f5;}
#messageArea .button{
color: #666;
border: 1px solid #CC6714;
}
#messageArea .button:hover {
color: #fff;
background: #948979;
border-color: #948979;
}
* html .viewer pre {
margin-left: 0em;
}
* html .editor textarea, * html .editor input {
width: 98%;
}
.searchBar {float:left;font-size: 1.0em;}
.searchBar .button {color:#999;display:block;}
.searchBar .button:hover {border:1px solid #fff;color:#4F4B45;}
.searchBar input {
background-color: #FFF;
color: #999999;
border: 1px solid #CCC;
margin-right:3px;
}
#sidebarOptions .button:active, #sidebarOptions .highlight {background:#F5F5F5;}
*html #contentFooter { padding:0.25em 1em 0.5em 1em;}
#noticeBoard {font-size: 0.9em; color:#999; position:relative;display:block;background:#fff; clear: both; margin-right:0.5em; margin-top:60px; padding:5px; border-bottom: 1px dotted #CCC; border-top: 1px dotted #CCC;}
#mainMenu #noticeBoard a,#mainMenu #noticeBoard .tiddlyLink {display:inline;border:none;padding:5px 2px;color:#DF9153 }
#noticeBoard a:hover {border:none;}
#noticeBoard br {display:inline;}
#mainMenu #noticeBoard .button{
color: #666;
border: 1px solid #DF9153;padding:2px;
}
#mainMenu #noticeBoard .button:hover{
color: #fff;
background: #DF9153;
border-color: #DF9153;
}
.searchbar {position:relative; width:11em;}
.searchbar .button{margin:0; width:11em;}
#header {display:inline-block;}
/*}}}*/
TaskBarTetris is Tetris in the Taskbar!
After opening a large number of windows, the icons in their taskbar buttons are used to create the playing field. Sounds useless? It is.
Watch the [[movie|./projects/taskbartetris/movies/taskbartetris.wmv]] (wmv, 1.5Mb).
[img[./projects/taskbartetris/images/tbt1.jpg]]
<html><object width="425" height="350"> <param name="movie" value="http://www.youtube.com/v/KlEl7iDpF08"> </param> <embed src="http://www.youtube.com/v/KlEl7iDpF08" type="application/x-shockwave-flash" width="425" height="350"> </embed> </object></html>
/***
|Name|TiddlerEncryptionPlugin|
|Author|Lyall Pearce|
|Source|http://www.Remotely-Helpful.com/TiddlyWiki/TiddlerEncryptionPlugin.html|
|License|[[Creative Commons Attribution-Share Alike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|Version|1.9.3|
|~CoreVersion|2.3.0|
|Requires|None|
|Overrides|store.getSaver().externalizeTiddler(), store.getTiddler() and store.getTiddlerText()|
|Description|Encrypt/Decrypt Tiddlers with a Password key|
!!!!!Usage
<<<
* Tag a tiddler with Encrypt(prompt)
** Consider the 'prompt' something to help you remember the password with. If multiple tiddlers can be encrypted with the same 'prompt' and you will only be asked for the password once.
* Upon save, the Tiddler will be encrypted and the tag replaced with Decrypt(prompt).
** Failure to encrypt (by not entering a password) will leave the tiddler unencrypted and will leave the Encrypt(prompt) tag in place. This means that the next time you save, you will be asked for the password again.
** To have multiple tiddlers use the same password - simply use the same 'prompt'.
** Tiddlers that are encrypted are also tagged 'excludeSearch' as there is no point in searching encrypted data - this is configurable by an option - you still may want to search the titles of encrypted tiddlers
** Encrypted tiddlers are stored as displayable hex, to keep things visibly tidy, should you display an encrypted tiddler. There is nothing worse than seeing a pile of gobbledy gook on your screen.
* Tiddlers are decrypted on initial display, not when you load the TiddlyWiki
** If you don't display a tiddler, you won't decrypt it.
** Tiddlers will re-encrypt automatically on save.
** Decryption of Tiddlers does not make your TiddlyWiki 'dirty' - you will not be asked to save if you leave the page.
* Errors are reported either by displaying the shadow tiddler DecryptionFailed or displaying the encrypted tiddler contents. This is configurable in AdvancedOptions
** Empty passwords, on save, will result in the tiddler being saved unencrypted - this should only occur with new tiddlers or with tiddlers who have had their 'prompt' tag changed.
** Encrypted tiddlers know if they are decrypted successfully - failure to decrypt a tiddler will ''not'' lose your data.
** Editing of an encrypted (that has not been unencrypted) tiddler will result in loss of that tiddler as the SHA1 checksums will no longer match, upon decryption. To this end, it is best that you do not check the option in AdvancedOptions
** To change the password on a Tiddler, change the Encrypt('prompt') tag to a new prompt value, after decrypting the tiddler.
** You can edit the tags of an encrypted tiddler, so long as you do not edit the text.
** To change the password for all tiddlers of a particular prompt, use the {{{<<EncryptionChangePassword ["button text" ["tooltip text" ["prompt string" ["accessKey"]]]]>>}}} macro.
** To decrypt all tiddlers of a particular "prompt string", use the {{{<<EncryptionDecryptAll ["button text" ["tooltip text" ["prompt string" ["accessKey"]]]]>>}}} macro - this will make tiddlers encrypted with "prompt string" searchable - or prompt for all 'prompt strings', if none is supplied.
<<<
!!!!!Revision History
<<<
* 1.0.0 - Initial release
* 1.1.0 - Cached passwords across tiddlers (not per tiddler) plus use Shadow tiddlers for display on failed decryptions.
* 1.2.0 - catch 'cancel' on password entry and options to not use the shadow tiddler reporting mechanism
* 1.3.0 - Change password caching mechansim slightly. Change the decryption hook so we now capture {{{<<tiddler encryptedTiddlers>>}}}. Ditched the shadow tiddler diagnostics - either display encrypted tiddler or pretend the encrypted tiddler does not exist, when decryption fails.
* 1.4.0 - Added Change password macro and decrypt all macro. Also make use of the displayMessage() method. <<EncryptionChangePassword>><<EncryptionDecryptAll>>
* 1.5.0 - Password change macro now has button text, tooltip and default prompt string parameters. Password change now sets store to dirty. Re-instated DecryptionFailed shadow tiddler, which is shown as tiddler contents if decryption fails and the AdvancedOptions checkbox is not checked.
* 1.5.1 - Invoke autosave after changing passwords - which may result in prompting for passwords of unencrypted tiddlers that require encryption and whose passwords have not been entered yet. Also improved integration with regard to retrieving tiddlerText
* 1.6.0 - Check for presence of PasswordPromptPlugin, if it's there, use it to enter passwords.
* 1.7.0 - Add option to turn off excludeSearch on encrypted Tiddlers - defaults to off and remove PasswordPromptPlugin support - it doesn't work.
* 1.8.0 - fixed source URL in metadata plus added accessKey (ALT-Shift key in FireFox) as the 4th parameter to the {{{<<EncryptionDecryptAll>>}}} and {{{<<EncryptionChangePassword>>}}} macros
* 1.9.0 - Add option to turn off password caching, so you are prompted for the password every time to decrypt a tiddler. The password is still kept for encrypting.
* 1.9.1 - Fix up core version number
* 1.9.2 - Uploaded the wrong version... sigh...
* 1.9.3 - Typo fixed
<<<
!!!!!Additional work
<<<
<<<
***/
//{{{
version.extensions.TiddlerEncryptionPlugin = {major: 1, minor: 9, revision: 3, date: new Date(2008,01,22)};
// where I cache the passwords - for want of a better place.
config.encryptionPasswords = new Array();
// Setup option for using shadow tiddlers for display of errors or simply show the 'encrypted tiddler'
if(config.options.chkEncryptShowEncrypted == undefined) config.options.chkEncryptShowEncrypted = false;
if(config.optionsDesc.chkEncryptShowEncrypted == undefined) config.optionsDesc.chkEncryptShowEncrypted = "TiddlerEncryptionPlugin\nShow encrypted tiddler contents on decrypt failure.\n<<EncryptionChangePassword>> - Change passwords of encrypted tiddlers\n<<EncryptionDecryptAll>> - Decrypt ALL tiddlers - enables searching.";
if(config.options.chkExcludeEncryptedFromSearch == undefined) config.options.chkExcludeEncryptedFromSearch = false;
if(config.optionsDesc.chkExcludeEncryptedFromSearch == undefined) config.optionsDesc.chkExcludeEncryptedFromSearch = "TiddlerEncryptionPlugin\nIf set, Encrypted Tiddlers are excluded from searching by tagging with excludeSearch. If Clear, excludeSearch is not added and it is also removed from existing Encrypted Tiddlers only if it is the last Tag. Searching of Encrypted Tiddlers is only meaningful for the Title and Tags.";
if(config.options.chkCachePasswords == undefined) config.options.chkCachePasswords = true;
if(config.optionsDesc.chkCachePasswords == undefined) config.optionsDesc.chkCachePasswords = "TiddlerEncryptionPlugin\nIf unchecked, do not cache passwords. This means you will be prompted for the password every time you display an encrypted tiddler (not forgetting that once they are displayed, they stay decrypted until the next save).";
config.shadowTiddlers.DecryptionFailed = "Decryption of an encrypted tiddler failed.";
config.macros.EncryptionChangePassword = {};
config.macros.EncryptionChangePassword.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
var theButton = createTiddlyButton(place,
(params[0] && params[0].length > 0) ? params[0] : "Change Passwords",
(params[1] && params[1].length > 0) ? params[1] : "Change Passwords" + (params[2] ? " for prompt "+params[2] : ""),
onClickEncryptionChangePassword,
null,
null,
params[3]);
if(params[2] && params[2].length > 0) {
theButton.setAttribute("promptString", params[2]);
}
};
config.macros.EncryptionDecryptAll = {};
config.macros.EncryptionDecryptAll.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
var theButton = createTiddlyButton(place,
(params[0] && params[0].length > 0) ? params[0] : "Decrypt All",
(params[1] && params[1].length > 0) ? params[1] : "Decrypt All Tiddlers" + ((params[2] && params[2].length > 0) ? " for prompt "+params[2] : " for a given 'prompt string'"),
onClickEncryptionDecryptAll,
null,
null,
params[3]);
if(params[2] && params[2].length > 0) {
theButton.setAttribute("promptString", params[2]);
}
};
function onClickEncryptionChangePassword() {
// Prompt for 'prompt string'
var promptString = this.getAttribute("promptString");
if(!promptString) {
promptString = prompt("Enter 'prompt string' to change password for:","");
}
if(!promptString) {
return;
}
// Prompt for 'old password'
var oldPassword = GetAndSetPasswordForPrompt_TiddlerEncryptionPlugin(promptString);
if(!oldPassword) {
return;
}
// Decrypt ALL tiddlers for that prompt
var decryptTag = "Decrypt("+promptString+")";
var tiddlersToDecrypt = store.getTaggedTiddlers(decryptTag);
try {
for(var ix=0; ix<tiddlersToDecrypt.length; ix++) {
CheckTiddlerForDecryption_TiddlerEncryptionPlugin(tiddlersToDecrypt[ix]);
}
} catch (e) {
if(e == "DecryptionFailed") {
displayMessage("Password incorrect.");
return;
} else {
throw e;
}
}
var newPassword = MyPrompt_TiddlerEncryptionPlugin("Enter new password for '"+promptString+"'", "");
if(newPassword) {
var newPasswordAgain = MyPrompt_TiddlerEncryptionPlugin("Enter new password, again, for '"+promptString+"'", "");
if(newPasswordAgain && newPassword == newPasswordAgain) {
if(config.optionsDesc.chkCachePasswords == false) {
config.encryptionPasswords[promptString] = newPasswordAgain;
}
displayMessage("Password for '"+promptString+"' updated.");
}
}
store.setDirty(true);
autoSaveChanges();
return;
};
function onClickEncryptionDecryptAll() {
var promptString = this.getAttribute("promptString");
if(!promptString) {
promptString = "";
}
var tagToSearchFor="Decrypt("+promptString;
try {
store.forEachTiddler(function(store,tiddler) {
if(tiddler && tiddler.tags) {
for(var ix=0; ix<tiddler.tags.length; ix++) {
if(tiddler.tags[ix].indexOf(tagToSearchFor) == 0) {
try {
CheckTiddlerForDecryption_TiddlerEncryptionPlugin(tiddler);
} catch (e) {
displayMessage("Decryption of '"+tiddler.title+"' failed.");
throw e;
}
} // if(tiddler.tags
} // for
} // if
}); // store.forEachTiddler
displayMessage("All encrypted tiddlers have been decrypted" + (promptString != "" ? "for '"+promptString+"'" : ""));
} catch (e) {
if(e == "DecryptionFailed") {
return;
}
} // catch
return;
};
store.getSaver().externalizeTiddler_TiddlerEncryptionPlugin = store.getSaver().externalizeTiddler;
store.getSaver().externalizeTiddler = function(store, tiddler) {
// Ok, got the tiddler, track down the passwordPrompt in the tags.
// track down the Encrypt(passwordPrompt) tag
if(tiddler && tiddler.tags) {
for(var g=0; g<tiddler.tags.length; g++) {
var tag = tiddler.tags[g];
if(tag.indexOf("Encrypt(") == 0) {
var lastBracket=tag.lastIndexOf(")");
if(lastBracket >= 0) {
// Ok, tagged with Encrypt(passwordPrompt)
// extract the passwordPrompt name
var passwordPrompt=tag.substring(8,lastBracket);
// Ok, Encrypt this tiddler!
var decryptedSHA1 = Crypto.hexSha1Str(tiddler.text);
var password = GetAndSetPasswordForPrompt_TiddlerEncryptionPlugin(passwordPrompt);
if(password) {
var encryptedText = TEAencrypt(tiddler.text, password);
encryptedText = StringToHext_TiddlerEncryptionPlugin(encryptedText);
tiddler.text = "Encrypted("+decryptedSHA1+")\n"+encryptedText;
// Replace the Tag with the Decrypt() tag
tiddler.tags[g]="Decrypt("+passwordPrompt+")";
// let the store know it's dirty
store.setDirty(tiddler.title, true);
// prevent searches on encrypted tiddlers, still nice to search on title though.
if(config.options.chkExcludeEncryptedFromSearch == true) {
tiddler.tags.push("excludeSearch");
}
} else {
// do not encrypt - no password entered
}
break;
} // if (lastBracket...
} // if(tag.indexOf(...
} // for(var g=0;...
} // if(tiddler.tags...
// Then, finally, do the save by calling the function we override.
return store.getSaver().externalizeTiddler_TiddlerEncryptionPlugin(store, tiddler);
};
function CheckTiddlerForDecryption_TiddlerEncryptionPlugin(tiddler) {
if(tiddler && tiddler.tags) {
for(var g=0; g<tiddler.tags.length; g++) {
var tag = tiddler.tags[g];
if(tag.indexOf("Decrypt(") == 0) {
var lastBracket=tag.lastIndexOf(")");
if(lastBracket >= 0) {
if(tiddler.text.substr(0,10) == "Encrypted(") {
var closingSHA1Bracket = tiddler.text.indexOf(")");
var decryptedSHA1 = tiddler.text.substring(10, closingSHA1Bracket);
// Ok, tagged with Decrypt(passwordPrompt)
// extract the passwordPrompt name
var passwordPrompt=tag.substring(8,lastBracket);
// Ok, Decrypt this tiddler!
var decryptedText = tiddler.text.substr(closingSHA1Bracket+2);
decryptedText = HexToString_TiddlerEncryptionPlugin(decryptedText);
var password = GetAndSetPasswordForPromptToDecrypt_TiddlerEncryptionPlugin(passwordPrompt);
if(password) {
decryptedText = TEAdecrypt(decryptedText, password );
var thisDecryptedSHA1 = Crypto.hexSha1Str(decryptedText);
if(decryptedSHA1 == thisDecryptedSHA1) {
tiddler.text = decryptedText;
// Replace the Tag with the Encrypt() tag
tiddler.tags[g]="Encrypt("+passwordPrompt+")";
if(tiddler.tags[tiddler.tags.length-1] == 'excludeSearch') {
// Remove exclude search only if it's the last entry
// as it's automatically put there by encryption
tiddler.tags.length--;
}
} else {
// Did not decrypt, discard the password from the cache
config.encryptionPasswords[passwordPrompt] = null;
throw "DecryptionFailed";
}
} else {
// no password supplied, dont bother trying to decrypt
throw "DecryptionFailed";
}
} else {
// Tagged as encrypted but not expected format, just leave it unchanged
}
break; // out of for loop
} // if (lastBracket...
} // if(tag.indexOf(...
} // for(var g=0;...
} // if (tiddler && tags)
return tiddler;
};
store.getTiddler_TiddlerEncryptionPlugin = store.getTiddler;
store.getTiddler = function(title) {
var tiddler = store.getTiddler_TiddlerEncryptionPlugin(title);
if(tiddler) { // shadow tiddlers are not expected to be encrypted.
try {
return CheckTiddlerForDecryption_TiddlerEncryptionPlugin(tiddler);
} catch (e) {
if(e == "DecryptionFailed") {
if(config.options.chkEncryptShowEncrypted) {
return tiddler;
} else {
var tiddler = store.getTiddler("DecryptionFailed");
if(!tiddler) {
tiddler = new Tiddler();
if(store.isShadowTiddler("DecryptionFailed")) {
tiddler.set(title,store.getTiddlerText("DecryptionFailed"),config.views.wikified.shadowModifier,version.date,[],version.date);
}
}
return tiddler;
}
}
} // catch
} // if(tiddler) {
return null;
};
store.getTiddlerText_TiddlerEncryptionPlugin = store.getTiddlerText;
store.getTiddlerText = function(title,defaultText) {
// Simply retrieve the tiddler, normally, if it requires decryption, it will be decrypted
var decryptedTiddler = store.getTiddler(title);
if(decryptedTiddler) {
return decryptedTiddler.text;
}
//Ok, rather than duplicate all the core code, the above code should fail if we reach here
// let the core code take over.
return store.getTiddlerText_TiddlerEncryptionPlugin(title,defaultText);
};
// Given a prompt, search our cache to see if we have already entered the password.
// Can return null if the user enters nothing.
function MyPrompt_TiddlerEncryptionPlugin(promptString,defaultValue) {
return prompt(promptString, defaultValue);
}
function GetAndSetPasswordForPrompt_TiddlerEncryptionPlugin(promptString) {
if(!config.encryptionPasswords[promptString]) {
config.encryptionPasswords[promptString] = MyPrompt_TiddlerEncryptionPlugin("Enter password for '"+promptString+"' :", "");
}
return config.encryptionPasswords[promptString]; // may be null, prompt can be cancelled.
}
function GetAndSetPasswordForPromptToDecrypt_TiddlerEncryptionPlugin(promptString) {
if(config.options.chkCachePasswords == true) {
return GetAndSetPasswordForPrompt_TiddlerEncryptionPlugin(promptString);
} else {
config.encryptionPasswords[promptString] = MyPrompt_TiddlerEncryptionPlugin("Enter password for '"+promptString+"' :", "");
return config.encryptionPasswords[promptString];
}
}
// Make the encrypted tiddlies look a little more presentable.
function StringToHext_TiddlerEncryptionPlugin(theString) {
var theResult = "";
for(var i=0; i<theString.length; i++) {
var theHex = theString.charCodeAt(i).toString(16);
if(theHex.length<2) {
theResult += "0"+theHex;
} else {
theResult += theHex;
}
if(i && i % 32 == 0)
theResult += "\n";
}
return theResult;
}
function HexToString_TiddlerEncryptionPlugin(theString) {
var theResult = "";
for(var i=0; i<theString.length; i+=2) {
if(theString.charAt(i) == "\n") {
i++;
}
theResult += String.fromCharCode(parseInt(theString.substr(i, 2),16));
}
return theResult;
}
// http://www.movable-type.co.uk/scripts/tea-block.html
//
// TEAencrypt: Use Corrected Block TEA to encrypt plaintext using password
// (note plaintext & password must be strings not string objects)
//
// Return encrypted text as string
//
function TEAencrypt(plaintext, password)
{
if (plaintext.length == 0) return(''); // nothing to encrypt
// 'escape' plaintext so chars outside ISO-8859-1 work in single-byte packing, but keep
// spaces as spaces (not '%20') so encrypted text doesn't grow too long (quick & dirty)
var asciitext = escape(plaintext).replace(/%20/g,' ');
var v = strToLongs(asciitext); // convert string to array of longs
if (v.length <= 1) v[1] = 0; // algorithm doesn't work for n<2 so fudge by adding a null
var k = strToLongs(password.slice(0,16)); // simply convert first 16 chars of password as key
var n = v.length;
var z = v[n-1], y = v[0], delta = 0x9E3779B9;
var mx, e, q = Math.floor(6 + 52/n), sum = 0;
while (q-- > 0) { // 6 + 52/n operations gives between 6 & 32 mixes on each word
sum += delta;
e = sum>>>2 & 3;
for (var p = 0; p < n; p++) {
y = v[(p+1)%n];
mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
z = v[p] += mx;
}
}
var ciphertext = longsToStr(v);
return escCtrlCh(ciphertext);
}
//
// TEAdecrypt: Use Corrected Block TEA to decrypt ciphertext using password
//
function TEAdecrypt(ciphertext, password)
{
if (ciphertext.length == 0) return('');
var v = strToLongs(unescCtrlCh(ciphertext));
var k = strToLongs(password.slice(0,16));
var n = v.length;
var z = v[n-1], y = v[0], delta = 0x9E3779B9;
var mx, e, q = Math.floor(6 + 52/n), sum = q*delta;
while (sum != 0) {
e = sum>>>2 & 3;
for (var p = n-1; p >= 0; p--) {
z = v[p>0 ? p-1 : n-1];
mx = (z>>>5 ^ y<<2) + (y>>>3 ^ z<<4) ^ (sum^y) + (k[p&3 ^ e] ^ z);
y = v[p] -= mx;
}
sum -= delta;
}
var plaintext = longsToStr(v);
// strip trailing null chars resulting from filling 4-char blocks:
plaintext = plaintext.replace(/\0+$/,'');
return unescape(plaintext);
}
// supporting functions
function strToLongs(s) { // convert string to array of longs, each containing 4 chars
// note chars must be within ISO-8859-1 (with Unicode code-point < 256) to fit 4/long
var l = new Array(Math.ceil(s.length/4));
for (var i=0; i<l.length; i++) {
// note little-endian encoding - endianness is irrelevant as long as
// it is the same in longsToStr()
l[i] = s.charCodeAt(i*4) + (s.charCodeAt(i*4+1)<<8) +
(s.charCodeAt(i*4+2)<<16) + (s.charCodeAt(i*4+3)<<24);
}
return l; // note running off the end of the string generates nulls since
} // bitwise operators treat NaN as 0
function longsToStr(l) { // convert array of longs back to string
var a = new Array(l.length);
for (var i=0; i<l.length; i++) {
a[i] = String.fromCharCode(l[i] & 0xFF, l[i]>>>8 & 0xFF,
l[i]>>>16 & 0xFF, l[i]>>>24 & 0xFF);
}
return a.join(''); // use Array.join() rather than repeated string appends for efficiency
}
function escCtrlCh(str) { // escape control chars etc which might cause problems with encrypted texts
return str.replace(/[\0\t\n\v\f\r\xa0'"!]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
}
function unescCtrlCh(str) { // unescape potentially problematic nulls and control characters
return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
}
//}}}
<<tiddler UploadPluginDoc>>
This form upload any file with an UploadService describe in [[Upload]]
----
<html><center>
<form enctype="multipart/form-data" action="store.php" method="post" target="_blank">
<input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
This file : <input name="userfile" type="file" /><p>
Options* : <input type="text" name="UploadPlugin" size=80 value="backupDir=BACKUP_DIR;uploaddir=UPLOAD_DIR;user=UPLOAD_USER;password=UPLOAD_PASSWORD;debug=0;" /><p>
<input type="submit" value="Upload" />
</form></center>
</html>
----
* Substitute BACKUP_DIR, UPLOAD_DIR, UPLOAD_USER and UPLOAD_PASSWORD with your values. See UploadPlugin for option details.
For security reason, don't save your password in a tiddler.
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 14/11/2008 18:34:17 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#%5B%5BMultitouch%20Fingerpaint%5D%5D]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 17/11/2008 11:27:56 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#%5B%5BMultitouch%20Fingerpaint%5D%5D]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:27:43 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:29:53 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:31:24 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:32:32 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:36:22 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:36:39 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:36:39 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
| 29/11/2008 00:39:38 | TomVL | [[index.html|file:///Users/tomvanlaerhoven/Projects/website/index.html#Personal]] | [[store.php|http://research.edm.uhasselt.be/tvanlaerhoven/store.php]] | . | [[index.html | http://research.edm.uhasselt.be/tvanlaerhoven/index.html]] | |
UploadPlugin uses the following sequence for finding parameters :
#''macro'' parameters
#''Options'' saved in cookies
#''Plugin'' default values
!Options used by UploadPlugin
| Option | Value | Default |
|Upload Username: |<<option txtUploadUserName>>| |
|Upload Password: |<<option pasUploadPassword>>| |
|Url of the UploadService script: |<<option txtUploadStoreUrl urlInput>>| store.php |
|Relative Directory where to store the file: |<<option txtUploadDir urlInput>>| . (the script directory) |
|Filename of the uploaded file: |<<option txtUploadFilename urlInput>>| index.html |
|Directory to backup file on webserver^^(1)^^: |<<option txtUploadBackupDir urlInput>>| //null// (none/no backup) |
|Log in UploadLog |<<option chkUploadLog>> Trace Upload| true |
|Maximum of lines in UploadLog |<<option txtUploadLogMaxLine>>| 10 |
^^(1)^^No backup if Backup Directory is empty, the previous file will be overwritten. Use a '.' to backup in the script directory.
<<upload>> with these options.
!Upload Macro parameters
{{{
<<upload [storeUrl [toFilename [backupDir [uploadDir [username]]]]]>>
Optional positional parameters can be passed to overwrite UploadOptions.
}}}
!UploadToFile Macro Macro parameters
{{{
<<uploadTofile [filename [tiddlerTitle]]>>
tiddlerTitle, filename: if omitted the title of the current tiddler
}}}
<<uploadToFile allowedsites.txt allowedsites.txt>>
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.1|
|''Date:''|Sep 15, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|
|''Documentation:''|http://tiddlywiki.bidix.info/#UploadPluginDoc|
|''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 (#3125)|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
major: 4, minor: 1, revision: 1,
date: new Date("Sep 15, 2007"),
source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
coreVersion: '2.2.0 (#3125)'
};
//
// Environment
//
if (!window.bidix) window.bidix = {}; // bidix namespace
bidix.debugMode = false; // true to activate both in Plugin and UploadService
//
// Upload Macro
//
config.macros.upload = {
// default values
defaultBackupDir: '', //no backup
defaultStoreScript: "store.php",
defaultToFilename: "index.html",
defaultUploadDir: ".",
authenticateUser: true // UploadService Authenticate User
};
config.macros.upload.label = {
promptOption: "Save and Upload this TiddlyWiki with UploadOptions",
promptParamMacro: "Save and Upload this TiddlyWiki in %0",
saveLabel: "save to web",
saveToDisk: "save to disk",
uploadLabel: "upload"
};
config.macros.upload.messages = {
noStoreUrl: "No store URL in parmeters or options",
usernameOrPasswordMissing: "Username or password missing"
};
config.macros.upload.handler = function(place,macroName,params) {
if (readOnly)
return;
var label;
if (document.location.toString().substr(0,4) == "http")
label = this.label.saveLabel;
else
label = this.label.uploadLabel;
var prompt;
if (params[0]) {
prompt = this.label.promptParamMacro.toString().format([this.destFile(params[0],
(params[1] ? params[1]:bidix.basename(window.location.toString())), params[3])]);
} else {
prompt = this.label.promptOption;
}
createTiddlyButton(place, label, prompt, function() {config.macros.upload.action(params);}, null, null, this.accessKey);
};
config.macros.upload.action = function(params)
{
// for missing macro parameter set value from options
var storeUrl = params[0] ? params[0] : config.options.txtUploadStoreUrl;
var toFilename = params[1] ? params[1] : config.options.txtUploadFilename;
var backupDir = params[2] ? params[2] : config.options.txtUploadBackupDir;
var uploadDir = params[3] ? params[3] : config.options.txtUploadDir;
var username = params[4] ? params[4] : config.options.txtUploadUserName;
var password = config.options.pasUploadPassword; // for security reason no password as macro parameter
// for still missing parameter set default value
if ((!storeUrl) && (document.location.toString().substr(0,4) == "http"))
storeUrl = bidix.dirname(document.location.toString())+'/'+config.macros.upload.defaultStoreScript;
if (storeUrl.substr(0,4) != "http")
storeUrl = bidix.dirname(document.location.toString()) +'/'+ storeUrl;
if (!toFilename)
toFilename = bidix.basename(window.location.toString());
if (!toFilename)
toFilename = config.macros.upload.defaultToFilename;
if (!uploadDir)
uploadDir = config.macros.upload.defaultUploadDir;
if (!backupDir)
backupDir = config.macros.upload.defaultBackupDir;
// report error if still missing
if (!storeUrl) {
alert(config.macros.upload.messages.noStoreUrl);
clearMessage();
return false;
}
if (config.macros.upload.authenticateUser && (!username || !password)) {
alert(config.macros.upload.messages.usernameOrPasswordMissing);
clearMessage();
return false;
}
bidix.upload.uploadChanges(false,null,storeUrl, toFilename, uploadDir, backupDir, username, password);
return false;
};
config.macros.upload.destFile = function(storeUrl, toFilename, uploadDir)
{
if (!storeUrl)
return null;
var dest = bidix.dirname(storeUrl);
if (uploadDir && uploadDir != '.')
dest = dest + '/' + uploadDir;
dest = dest + '/' + toFilename;
return dest;
};
//
// uploadOptions Macro
//
config.macros.uploadOptions = {
handler: function(place,macroName,params) {
var wizard = new Wizard();
wizard.createWizard(place,this.wizardTitle);
wizard.addStep(this.step1Title,this.step1Html);
var markList = wizard.getElement("markList");
var listWrapper = document.createElement("div");
markList.parentNode.insertBefore(listWrapper,markList);
wizard.setValue("listWrapper",listWrapper);
this.refreshOptions(listWrapper,false);
var uploadCaption;
if (document.location.toString().substr(0,4) == "http")
uploadCaption = config.macros.upload.label.saveLabel;
else
uploadCaption = config.macros.upload.label.uploadLabel;
wizard.setButtons([
{caption: uploadCaption, tooltip: config.macros.upload.label.promptOption,
onClick: config.macros.upload.action},
{caption: this.cancelButton, tooltip: this.cancelButtonPrompt, onClick: this.onCancel}
]);
},
refreshOptions: function(listWrapper) {
var uploadOpts = [
"txtUploadUserName",
"pasUploadPassword",
"txtUploadStoreUrl",
"txtUploadDir",
"txtUploadFilename",
"txtUploadBackupDir",
"chkUploadLog",
"txtUploadLogMaxLine",
]
var opts = [];
for(i=0; i<uploadOpts.length; i++) {
var opt = {};
opts.push()
opt.option = "";
n = uploadOpts[i];
opt.name = n;
opt.lowlight = !config.optionsDesc[n];
opt.description = opt.lowlight ? this.unknownDescription : config.optionsDesc[n];
opts.push(opt);
}
var listview = ListView.create(listWrapper,opts,this.listViewTemplate);
for(n=0; n<opts.length; n++) {
var type = opts[n].name.substr(0,3);
var h = config.macros.option.types[type];
if (h && h.create) {
h.create(opts[n].colElements['option'],type,opts[n].name,opts[n].name,"no");
}
}
},
onCancel: function(e)
{
backstage.switchTab(null);
return false;
},
wizardTitle: "Upload with options",
step1Title: "These options are saved in cookies in your browser",
step1Html: "<input type='hidden' name='markList'></input><br>",
cancelButton: "Cancel",
cancelButtonPrompt: "Cancel prompt",
listViewTemplate: {
columns: [
{name: 'Description', field: 'description', title: "Description", type: 'WikiText'},
{name: 'Option', field: 'option', title: "Option", type: 'String'},
{name: 'Name', field: 'name', title: "Name", type: 'String'}
],
rowClasses: [
{className: 'lowlight', field: 'lowlight'}
]}
}
//
// upload functions
//
if (!bidix.upload) bidix.upload = {};
if (!bidix.upload.messages) bidix.upload.messages = {
//from saving
invalidFileError: "The original file '%0' does not appear to be a valid TiddlyWiki",
backupSaved: "Backup saved",
backupFailed: "Failed to upload backup file",
rssSaved: "RSS feed uploaded",
rssFailed: "Failed to upload RSS feed file",
emptySaved: "Empty template uploaded",
emptyFailed: "Failed to upload empty template file",
mainSaved: "Main TiddlyWiki file uploaded",
mainFailed: "Failed to upload main TiddlyWiki file. Your changes have not been saved",
//specific upload
loadOriginalHttpPostError: "Can't get original file",
aboutToSaveOnHttpPost: 'About to upload on %0 ...',
storePhpNotFound: "The store script '%0' was not found."
};
bidix.upload.uploadChanges = function(onlyIfDirty,tiddlers,storeUrl,toFilename,uploadDir,backupDir,username,password)
{
var callback = function(status,uploadParams,original,url,xhr) {
if (!status) {
displayMessage(bidix.upload.messages.loadOriginalHttpPostError);
return;
}
if (bidix.debugMode)
alert(original.substr(0,500)+"\n...");
// Locate the storeArea div's
var posDiv = locateStoreArea(original);
if((posDiv[0] == -1) || (posDiv[1] == -1)) {
alert(config.messages.invalidFileError.format([localPath]));
return;
}
bidix.upload.uploadRss(uploadParams,original,posDiv);
};
if(onlyIfDirty && !store.isDirty())
return;
clearMessage();
// save on localdisk ?
if (document.location.toString().substr(0,4) == "file") {
var path = document.location.toString();
var localPath = getLocalPath(path);
saveChanges();
}
// get original
var uploadParams = Array(storeUrl,toFilename,uploadDir,backupDir,username,password);
var originalPath = document.location.toString();
// If url is a directory : add index.html
if (originalPath.charAt(originalPath.length-1) == "/")
originalPath = originalPath + "index.html";
var dest = config.macros.upload.destFile(storeUrl,toFilename,uploadDir);
var log = new bidix.UploadLog();
log.startUpload(storeUrl, dest, uploadDir, backupDir);
displayMessage(bidix.upload.messages.aboutToSaveOnHttpPost.format([dest]));
if (bidix.debugMode)
alert("about to execute Http - GET on "+originalPath);
var r = doHttp("GET",originalPath,null,null,null,null,callback,uploadParams,null);
if (typeof r == "string")
displayMessage(r);
return r;
};
bidix.upload.uploadRss = function(uploadParams,original,posDiv)
{
var callback = function(status,params,responseText,url,xhr) {
if(status) {
var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
displayMessage(bidix.upload.messages.rssSaved,bidix.dirname(url)+'/'+destfile);
bidix.upload.uploadMain(params[0],params[1],params[2]);
} else {
displayMessage(bidix.upload.messages.rssFailed);
}
};
// do uploadRss
if(config.options.chkGenerateAnRssFeed) {
var rssPath = uploadParams[1].substr(0,uploadParams[1].lastIndexOf(".")) + ".xml";
var rssUploadParams = Array(uploadParams[0],rssPath,uploadParams[2],'',uploadParams[4],uploadParams[5]);
var rssString = generateRss();
// no UnicodeToUTF8 conversion needed when location is "file" !!!
if (document.location.toString().substr(0,4) != "file")
rssString = convertUnicodeToUTF8(rssString);
bidix.upload.httpUpload(rssUploadParams,rssString,callback,Array(uploadParams,original,posDiv));
} else {
bidix.upload.uploadMain(uploadParams,original,posDiv);
}
};
bidix.upload.uploadMain = function(uploadParams,original,posDiv)
{
var callback = function(status,params,responseText,url,xhr) {
var log = new bidix.UploadLog();
if(status) {
// if backupDir specified
if ((params[3]) && (responseText.indexOf("backupfile:") > -1)) {
var backupfile = responseText.substring(responseText.indexOf("backupfile:")+11,responseText.indexOf("\n", responseText.indexOf("backupfile:")));
displayMessage(bidix.upload.messages.backupSaved,bidix.dirname(url)+'/'+backupfile);
}
var destfile = responseText.substring(responseText.indexOf("destfile:")+9,responseText.indexOf("\n", responseText.indexOf("destfile:")));
displayMessage(bidix.upload.messages.mainSaved,bidix.dirname(url)+'/'+destfile);
store.setDirty(false);
log.endUpload("ok");
} else {
alert(bidix.upload.messages.mainFailed);
displayMessage(bidix.upload.messages.mainFailed);
log.endUpload("failed");
}
};
// do uploadMain
var revised = bidix.upload.updateOriginal(original,posDiv);
bidix.upload.httpUpload(uploadParams,revised,callback,uploadParams);
};
bidix.upload.httpUpload = function(uploadParams,data,callback,params)
{
var localCallback = function(status,params,responseText,url,xhr) {
url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
if (xhr.status == httpStatus.NotFound)
alert(bidix.upload.messages.storePhpNotFound.format([url]));
if ((bidix.debugMode) || (responseText.indexOf("Debug mode") >= 0 )) {
alert(responseText);
if (responseText.indexOf("Debug mode") >= 0 )
responseText = responseText.substring(responseText.indexOf("\n\n")+2);
} else if (responseText.charAt(0) != '0')
alert(responseText);
if (responseText.charAt(0) != '0')
status = null;
callback(status,params,responseText,url,xhr);
};
// do httpUpload
var boundary = "---------------------------"+"AaB03x";
var uploadFormName = "UploadPlugin";
// compose headers data
var sheader = "";
sheader += "--" + boundary + "\r\nContent-disposition: form-data; name=\"";
sheader += uploadFormName +"\"\r\n\r\n";
sheader += "backupDir="+uploadParams[3] +
";user=" + uploadParams[4] +
";password=" + uploadParams[5] +
";uploaddir=" + uploadParams[2];
if (bidix.debugMode)
sheader += ";debug=1";
sheader += ";;\r\n";
sheader += "\r\n" + "--" + boundary + "\r\n";
sheader += "Content-disposition: form-data; name=\"userfile\"; filename=\""+uploadParams[1]+"\"\r\n";
sheader += "Content-Type: text/html;charset=UTF-8" + "\r\n";
sheader += "Content-Length: " + data.length + "\r\n\r\n";
// compose trailer data
var strailer = new String();
strailer = "\r\n--" + boundary + "--\r\n";
data = sheader + data + strailer;
if (bidix.debugMode) alert("about to execute Http - POST on "+uploadParams[0]+"\n with \n"+data.substr(0,500)+ " ... ");
var r = doHttp("POST",uploadParams[0],data,"multipart/form-data; boundary="+boundary,uploadParams[4],uploadParams[5],localCallback,params,null);
if (typeof r == "string")
displayMessage(r);
return r;
};
// same as Saving's updateOriginal but without convertUnicodeToUTF8 calls
bidix.upload.updateOriginal = function(original, posDiv)
{
if (!posDiv)
posDiv = locateStoreArea(original);
if((posDiv[0] == -1) || (posDiv[1] == -1)) {
alert(config.messages.invalidFileError.format([localPath]));
return;
}
var revised = original.substr(0,posDiv[0] + startSaveArea.length) + "\n" +
store.allTiddlersAsHtml() + "\n" +
original.substr(posDiv[1]);
var newSiteTitle = getPageTitle().htmlEncode();
revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");
revised = updateMarkupBlock(revised,"PRE-HEAD","MarkupPreHead");
revised = updateMarkupBlock(revised,"POST-HEAD","MarkupPostHead");
revised = updateMarkupBlock(revised,"PRE-BODY","MarkupPreBody");
revised = updateMarkupBlock(revised,"POST-SCRIPT","MarkupPostBody");
return revised;
};
//
// UploadLog
//
// config.options.chkUploadLog :
// false : no logging
// true : logging
// config.options.txtUploadLogMaxLine :
// -1 : no limit
// 0 : no Log lines but UploadLog is still in place
// n : the last n lines are only kept
// NaN : no limit (-1)
bidix.UploadLog = function() {
if (!config.options.chkUploadLog)
return; // this.tiddler = null
this.tiddler = store.getTiddler("UploadLog");
if (!this.tiddler) {
this.tiddler = new Tiddler();
this.tiddler.title = "UploadLog";
this.tiddler.text = "| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |";
this.tiddler.created = new Date();
this.tiddler.modifier = config.options.txtUserName;
this.tiddler.modified = new Date();
store.addTiddler(this.tiddler);
}
return this;
};
bidix.UploadLog.prototype.addText = function(text) {
if (!this.tiddler)
return;
// retrieve maxLine when we need it
var maxLine = parseInt(config.options.txtUploadLogMaxLine,10);
if (isNaN(maxLine))
maxLine = -1;
// add text
if (maxLine != 0)
this.tiddler.text = this.tiddler.text + text;
// Trunck to maxLine
if (maxLine >= 0) {
var textArray = this.tiddler.text.split('\n');
if (textArray.length > maxLine + 1)
textArray.splice(1,textArray.length-1-maxLine);
this.tiddler.text = textArray.join('\n');
}
// update tiddler fields
this.tiddler.modifier = config.options.txtUserName;
this.tiddler.modified = new Date();
store.addTiddler(this.tiddler);
// refresh and notifiy for immediate update
story.refreshTiddler(this.tiddler.title);
store.notify(this.tiddler.title, true);
};
bidix.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir, backupDir) {
if (!this.tiddler)
return;
var now = new Date();
var text = "\n| ";
var filename = bidix.basename(document.location.toString());
if (!filename) filename = '/';
text += now.formatString("0DD/0MM/YYYY 0hh:0mm:0ss") +" | ";
text += config.options.txtUserName + " | ";
text += "[["+filename+"|"+location + "]] |";
text += " [[" + bidix.basename(storeUrl) + "|" + storeUrl + "]] | ";
text += uploadDir + " | ";
text += "[[" + bidix.basename(toFilename) + " | " +toFilename + "]] | ";
text += backupDir + " |";
this.addText(text);
};
bidix.UploadLog.prototype.endUpload = function(status) {
if (!this.tiddler)
return;
this.addText(" "+status+" |");
};
//
// Utilities
//
bidix.checkPlugin = function(plugin, major, minor, revision) {
var ext = version.extensions[plugin];
if (!
(ext &&
((ext.major > major) ||
((ext.major == major) && (ext.minor > minor)) ||
((ext.major == major) && (ext.minor == minor) && (ext.revision >= revision))))) {
// write error in PluginManager
if (pluginInfo)
pluginInfo.log.push("Requires " + plugin + " " + major + "." + minor + "." + revision);
eval(plugin); // generate an error : "Error: ReferenceError: xxxx is not defined"
}
};
bidix.dirname = function(filePath) {
if (!filePath)
return;
var lastpos;
if ((lastpos = filePath.lastIndexOf("/")) != -1) {
return filePath.substring(0, lastpos);
} else {
return filePath.substring(0, filePath.lastIndexOf("\\"));
}
};
bidix.basename = function(filePath) {
if (!filePath)
return;
var lastpos;
if ((lastpos = filePath.lastIndexOf("#")) != -1)
filePath = filePath.substring(0, lastpos);
if ((lastpos = filePath.lastIndexOf("/")) != -1) {
return filePath.substring(lastpos + 1);
} else
return filePath.substring(filePath.lastIndexOf("\\")+1);
};
bidix.initOption = function(name,value) {
if (!config.options[name])
config.options[name] = value;
};
//
// Initializations
//
// require PasswordOptionPlugin 1.0.1 or better
bidix.checkPlugin("PasswordOptionPlugin", 1, 0, 1);
// styleSheet
setStylesheet('.txtUploadStoreUrl, .txtUploadBackupDir, .txtUploadDir {width: 22em;}',"uploadPluginStyles");
//optionsDesc
merge(config.optionsDesc,{
txtUploadStoreUrl: "Url of the UploadService script (default: store.php)",
txtUploadFilename: "Filename of the uploaded file (default: in index.html)",
txtUploadDir: "Relative Directory where to store the file (default: . (downloadService directory))",
txtUploadBackupDir: "Relative Directory where to backup the file. If empty no backup. (default: ''(empty))",
txtUploadUserName: "Upload Username",
pasUploadPassword: "Upload Password",
chkUploadLog: "do Logging in UploadLog (default: true)",
txtUploadLogMaxLine: "Maximum of lines in UploadLog (default: 10)"
});
// Options Initializations
bidix.initOption('txtUploadStoreUrl','');
bidix.initOption('txtUploadFilename','');
bidix.initOption('txtUploadDir','');
bidix.initOption('txtUploadBackupDir','');
bidix.initOption('txtUploadUserName','');
bidix.initOption('pasUploadPassword','');
bidix.initOption('chkUploadLog',true);
bidix.initOption('txtUploadLogMaxLine','10');
// Backstage
merge(config.tasks,{
uploadOptions: {text: "upload", tooltip: "Change UploadOptions and Upload", content: '<<uploadOptions>>'}
});
config.backstageTasks.push("uploadOptions");
//}}}
{{{
var TiddlyLock = {}; // Create a namespace for our new function.
TiddlyLock.displayTiddler = story.displayTiddler;
story.displayTiddler = function(srcElement,titles,template,unused1,unused2,animate,unused3)
{
if (urchinTracker) { urchinTracker('/' + titles); }
TiddlyLock.displayTiddler.apply(this,arguments);
}
}}}
/***
|''Name''|WebStatsPlugin|
|''Version''|0.1|
|''Author''|Tom Van Laerhoven|
|''Source''|[[Tom Van Laerhoven's page|http://research.uhasselt.be/tvanlaerhoven/#WebStatsPlugin]]|
|''License''|none|
|''~CoreVersion''|2.1|
|''Type''|macro|
|''Requires''|N/A|
|''Overrides''|N/A|
|''Description''|Includes code for webstat tools.|
!Notes
Made for own purposes.
!Usage
{{{
<<writeBelStats>>
}}}
!!Example
!Revision History
!!v0.1 (2008-02-02)
* initial release
!Code
***/
//{{{
config.macros.writeBelStats = {
handler: function (place, macroName, params, wikifier, paramString, tiddler)
{
var contents ="";
d=document;
col="";scr=0;b=navigator.appName;
scr=screen.width+"*"+screen.height;
ref=parent==self ? escape(window.document.referrer) : escape(top.document.referrer);
pag=escape(document.URL);
if (b != "Netscape") {col=screen.colorDepth}
else {col=screen.pixelDepth}
if(col=="undefined")
{
col="";
}
contents += "<html>";
contents += "<a href=http://www.belstat.be/viewstat.asp?UserID=pakewak&lang=en target=_blank><img border=0 src=\"http://www.belstat.be/regstat.aspx?";
contents += "UserID=pakewak&BColor=&refer=" + ref + "&pag=" + pag + "&b=" + b + "&col=" + col + "&scr=" + scr;
contents += "\" align=center width=16 height=16 alt=\"Monitored by BelStat - Your Site Counts\"><\/a>";
contents += "</html>";
wikify(contents, place);
}
};
//}}}
A [[DTD|./projects/xgl/xgl_120503.dtd]] (12-05-03) of the XGL standard, based upon the official XGL specifications. An older version (14-07-01) can also be found on the [[XML cover pages|http://xml.coverpages.org/XGL-DTD-200103.txt]].
Example XGL files, taken from the [[XGL specs page|http://www.xglspec.org/]], and patched to meet the DTD requirements:
[[Two Green Cubes XGL|./projects/xgl/greencubes.xgl]]
[[A Bee XGL|./projects/xgl/bee.xgl]]
[[A Legoman XGL|./projects/xgl/legoman.xgl]]
[[TiddlyWiki|http://www.tiddlywiki.com]] Ā© Osmosoft
A small cgi script that probes a list of [[distcc|http://distcc.samba.org/]] daemons. The output is a webpage containing up/down status information for each host.
[img[./projects/distccwebview/distccwebview_v002.jpg]]
*[[distccwebview_v003.tar.gz|./projects/distccwebview/distccwebview_v003.tar.gz]] (02-06-08)
**[[ChangeLog|./projects/distccwebview/ChangeLog_v003]]
*[[distccwebview_v002.tar.gz|./projects/distccwebview/distccwebview_v002.tar.gz]] (08-15-03)
**[[ChangeLog|./projects/distccwebview/ChangeLog_v002]]
*[[distccwebview_v001.tar.gz|./projects/distccwebview/distccwebview_v001.tar.gz]] (07-21-03)
//{{{
//This ensures that the footer sticks to the bottom of the screen when there are no tiddlers open. If that is not desirable, it can be deleted.
function setFooter() {
if (document.getElementById && document.getElementById("contentFooter") ) {
var windowHeight=findWindowHeight();
if (windowHeight>0) {
var contentHeight= document.getElementById('mainMenu').offsetHeight + document.getElementById("header").offsetHeight + document.getElementById("contentFooter").offsetHeight;
var menu= document.getElementById('mainMenu');
if (windowHeight-(contentHeight)>=0) {
menu.style.position='relative';
menu.style.marginBottom=(windowHeight-(contentHeight))+'px';
}
else {
menu.style.position='';
menu.style.marginBottom='';
}
}
}
}
window.onresize = function() {
setFooter();
}
Story.prototype.refreshTiddler_footerhack=Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function (title,template,force)
{
var theTiddler = Story.prototype.refreshTiddler_footerhack.apply(this,arguments);
setFooter();
return theTiddler;}
//}}}
//{{{
config.options.chkAutoSave = true;
config.options.chkAnimate = false;
config.options.txtUserName = "TomVL";
config.options.chkSinglePageMode = true;
config.options.chkTopOfPageMode = true;
config.options.chkSinglePagePermalink = true;
//}}}