Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
<<reminder day:2 month:7 year:2009 recurdays:28 title:"recur">>
<<reminder day:31 month:7 year:2009 title:"reminder title here">>
/***
|Name|CalendarPlugin|
|Source|http://www.TiddlyTools.com/#CalendarPlugin|
|Version|1.5.0|
|Author|Eric Shulman|
|Original Author|SteveRumsby|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|display monthly and yearly calendars|
NOTE: For //enhanced// date popup display, optionally install [[DatePlugin]] and [[ReminderMacros]]
!!!Usage:
<<<
|{{{<<calendar>>}}}|full-year calendar for the current year|
|{{{<<calendar year>>}}}|full-year calendar for the specified year|
|{{{<<calendar year month>>}}}|one month calendar for the specified month and year|
|{{{<<calendar thismonth>>}}}|one month calendar for the current month|
|{{{<<calendar lastmonth>>}}}|one month calendar for last month|
|{{{<<calendar nextmonth>>}}}|one month calendar for next month|
|{{{<<calendar +n>>}}}<br>{{{<<calendar -n>>}}}|one month calendar for a month +/- 'n' months from now|
<<<
!!!Configuration:
<<<
|''First day of week:''<br>{{{config.options.txtCalFirstDay}}}|<<option txtCalFirstDay>>|(Monday = 0, Sunday = 6)|
|''First day of weekend:''<br>{{{config.options.txtCalStartOfWeekend}}}|<<option txtCalStartOfWeekend>>|(Monday = 0, Sunday = 6)|
<<option chkDisplayWeekNumbers>> Display week numbers //(note: Monday will be used as the start of the week)//
|''Week number display format:''<br>{{{config.options.txtWeekNumberDisplayFormat }}}|<<option txtWeekNumberDisplayFormat >>|
|''Week number link format:''<br>{{{config.options.txtWeekNumberLinkFormat }}}|<<option txtWeekNumberLinkFormat >>|
<<<
!!!Revisions
<<<
2009.04.31 [1.5.0] rewrote onClickCalendarDate() (popup handler) and added config.options.txtCalendarReminderTags. Partial code reduction/cleanup. Assigned true version number (1.5.0)
2008.09.10 added '+n' (and '-n') param to permit display of relative months (e.g., '+6' means 'six months from now', '-3' means 'three months ago'. Based on suggestion from Jean.
2008.06.17 added support for config.macros.calendar.todaybg
2008.02.27 in handler(), DON'T set hard-coded default date format, so that *customized* value (pre-defined in config.macros.calendar.journalDateFmt is used.
2008.02.17 in createCalendarYear(), fix next/previous year calculation (use parseInt() to convert to numeric value). Also, use journalDateFmt for date linking when NOT using [[DatePlugin]].
2008.02.16 in createCalendarDay(), week numbers now created as TiddlyLinks, allowing quick creation/navigation to 'weekly' journals (based on request from Kashgarinn)
2008.01.08 in createCalendarMonthHeader(), 'month year' heading is now created as TiddlyLink, allowing quick creation/navigation to 'month-at-a-time' journals
2007.11.30 added 'return false' to onclick handlers (prevent IE from opening blank pages)
2006.08.23 added handling for weeknumbers (code supplied by Martin Budden (see 'wn**' comment marks). Also, incorporated updated by Jeremy Sheeley to add caching for reminders (see [[ReminderMacros]], if installed)
2005.10.30 in config.macros.calendar.handler(), use 'tbody' element for IE compatibility. Also, fix year calculation for IE's getYear() function (which returns '2005' instead of '105'). Also, in createCalendarDays(), use showDate() function (see [[DatePlugin]], if installed) to render autostyled date with linked popup. Updated calendar stylesheet definition: use .calendar class-specific selectors, add text centering and margin settings
2006.05.29 added journalDateFmt handling
<<<
!!!Code
***/
//{{{
version.extensions.CalendarPlugin= { major: 1, minor: 5, revision: 0, date: new Date(2009,5,31)};
//}}}
//{{{
if(config.options.txtCalFirstDay == undefined)
config.options.txtCalFirstDay = 0;
if(config.options.txtCalStartOfWeekend == undefined)
config.options.txtCalStartOfWeekend = 5;
if(config.options.chkDisplayWeekNumbers == undefined)
config.options.chkDisplayWeekNumbers = false;
if(config.options.chkDisplayWeekNumbers)
config.options.txtCalFirstDay = 0;
if(config.options.txtWeekNumberDisplayFormat == undefined)
config.options.txtWeekNumberDisplayFormat = 'w0WW';
if(config.options.txtWeekNumberLinkFormat == undefined)
config.options.txtWeekNumberLinkFormat = 'YYYY-w0WW';
if(config.options.txtCalendarReminderTags == undefined)
config.options.txtCalendarReminderTags = 'reminder';
config.macros.calendar = {
monthnames:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
daynames:['M','T','W','T','F','S','S'],
todaybg:'#ccccff',
weekendbg:'#c0c0c0',
monthbg:'#e0e0e0',
holidaybg:'#ffc0c0',
journalDateFmt:'DD MMM YYYY',
monthdays:[31,28,31,30,31,30,31,31,30,31,30,31],
holidays:[ ] // for customization see [[CalendarPluginConfig]]
};
//}}}
//{{{
function calendarIsHoliday(date)
{
var longHoliday = date.formatString('0DD/0MM/YYYY');
var shortHoliday = date.formatString('0DD/0MM');
for(var i = 0; i < config.macros.calendar.holidays.length; i++) {
if( config.macros.calendar.holidays[i]==longHoliday
|| config.macros.calendar.holidays[i]==shortHoliday)
return true;
}
return false;
}
//}}}
//{{{
config.macros.calendar.handler = function(place,macroName,params) {
var calendar = createTiddlyElement(place, 'table', null, 'calendar', null);
var tbody = createTiddlyElement(calendar, 'tbody');
var today = new Date();
var year = today.getYear();
if (year<1900) year+=1900;
// get journal format from SideBarOptions (ELS 5/29/06 - suggested by MartinBudden)
var text = store.getTiddlerText('SideBarOptions');
var re = new RegExp('<<(?:newJournal)([^>]*)>>','mg'); var fm = re.exec(text);
if (fm && fm[1]!=null) { var pa=fm[1].readMacroParams(); if (pa[0]) this.journalDateFmt = pa[0]; }
var month=-1;
if (params[0] == 'thismonth') {
var month=today.getMonth();
} else if (params[0] == 'lastmonth') {
var month = today.getMonth()-1; if (month==-1) { month=11; year--; }
} else if (params[0] == 'nextmonth') {
var month = today.getMonth()+1; if (month>11) { month=0; year++; }
} else if (params[0]&&'+-'.indexOf(params[0].substr(0,1))!=-1) {
var month = today.getMonth()+parseInt(params[0]);
if (month>11) { year+=Math.floor(month/12); month%=12; };
if (month<0) { year+=Math.floor(month/12); month=12+month%12; }
} else if (params[0]) {
year = params[0];
if(params[1]) month=parseInt(params[1])-1;
if (month>11) month=11; if (month<0) month=0;
}
if (month!=-1) {
cacheReminders(new Date(year, month, 1, 0, 0), 31);
createCalendarOneMonth(tbody, year, month);
} else {
cacheReminders(new Date(year, 0, 1, 0, 0), 366);
createCalendarYear(tbody, year);
}
window.reminderCacheForCalendar = null;
}
//}}}
//{{{
// cache used to store reminders while the calendar is being rendered
// it will be renulled after the calendar is fully rendered.
window.reminderCacheForCalendar = null;
//}}}
//{{{
function cacheReminders(date, leadtime)
{
if (window.findTiddlersWithReminders == null) return;
window.reminderCacheForCalendar = {};
var leadtimeHash = [];
leadtimeHash [0] = 0;
leadtimeHash [1] = leadtime;
var t = findTiddlersWithReminders(date, leadtimeHash, null, 1);
for(var i = 0; i < t.length; i++) {
//just tag it in the cache, so that when we're drawing days, we can bold this one.
window.reminderCacheForCalendar[t[i]['matchedDate']] = 'reminder:' + t[i]['params']['title'];
}
}
//}}}
//{{{
function createCalendarOneMonth(calendar, year, mon)
{
var row = createTiddlyElement(calendar, 'tr');
createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon]+' '+year, true, year, mon);
row = createTiddlyElement(calendar, 'tr');
createCalendarDayHeader(row, 1);
createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarMonth(calendar, year, mon)
{
var row = createTiddlyElement(calendar, 'tr');
createCalendarMonthHeader(calendar, row, config.macros.calendar.monthnames[mon]+' '+ year, false, year, mon);
row = createTiddlyElement(calendar, 'tr');
createCalendarDayHeader(row, 1);
createCalendarDayRowsSingle(calendar, year, mon);
}
//}}}
//{{{
function createCalendarYear(calendar, year)
{
var row;
row = createTiddlyElement(calendar, 'tr');
var back = createTiddlyElement(row, 'td');
var backHandler = function() {
removeChildren(calendar);
createCalendarYear(calendar, parseInt(year)-1);
return false; // consume click
};
createTiddlyButton(back, '<', 'Previous year', backHandler);
back.align = 'center';
var yearHeader = createTiddlyElement(row, 'td', null, 'calendarYear', year);
yearHeader.align = 'center';
yearHeader.setAttribute('colSpan',config.options.chkDisplayWeekNumbers?22:19);//wn**
var fwd = createTiddlyElement(row, 'td');
var fwdHandler = function() {
removeChildren(calendar);
createCalendarYear(calendar, parseInt(year)+1);
return false; // consume click
};
createTiddlyButton(fwd, '>', 'Next year', fwdHandler);
fwd.align = 'center';
createCalendarMonthRow(calendar, year, 0);
createCalendarMonthRow(calendar, year, 3);
createCalendarMonthRow(calendar, year, 6);
createCalendarMonthRow(calendar, year, 9);
}
//}}}
//{{{
function createCalendarMonthRow(cal, year, mon)
{
var row = createTiddlyElement(cal, 'tr');
createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon], false, year, mon);
createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+1], false, year, mon);
createCalendarMonthHeader(cal, row, config.macros.calendar.monthnames[mon+2], false, year, mon);
row = createTiddlyElement(cal, 'tr');
createCalendarDayHeader(row, 3);
createCalendarDayRows(cal, year, mon);
}
//}}}
//{{{
function createCalendarMonthHeader(cal, row, name, nav, year, mon)
{
var month;
if (nav) {
var back = createTiddlyElement(row, 'td');
back.align = 'center';
back.style.background = config.macros.calendar.monthbg;
var backMonHandler = function() {
var newyear = year;
var newmon = mon-1;
if(newmon == -1) { newmon = 11; newyear = newyear-1;}
removeChildren(cal);
cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
createCalendarOneMonth(cal, newyear, newmon);
return false; // consume click
};
createTiddlyButton(back, '<', 'Previous month', backMonHandler);
month = createTiddlyElement(row, 'td', null, 'calendarMonthname')
createTiddlyLink(month,name,true);
month.setAttribute('colSpan', config.options.chkDisplayWeekNumbers?6:5);//wn**
var fwd = createTiddlyElement(row, 'td');
fwd.align = 'center';
fwd.style.background = config.macros.calendar.monthbg;
var fwdMonHandler = function() {
var newyear = year;
var newmon = mon+1;
if(newmon == 12) { newmon = 0; newyear = newyear+1;}
removeChildren(cal);
cacheReminders(new Date(newyear, newmon , 1, 0, 0), 31);
createCalendarOneMonth(cal, newyear, newmon);
return false; // consume click
};
createTiddlyButton(fwd, '>', 'Next month', fwdMonHandler);
} else {
month = createTiddlyElement(row, 'td', null, 'calendarMonthname', name)
month.setAttribute('colSpan',config.options.chkDisplayWeekNumbers?8:7);//wn**
}
month.align = 'center';
month.style.background = config.macros.calendar.monthbg;
}
//}}}
//{{{
function createCalendarDayHeader(row, num)
{
var cell;
for(var i = 0; i < num; i++) {
if (config.options.chkDisplayWeekNumbers) createTiddlyElement(row, 'td');//wn**
for(var j = 0; j < 7; j++) {
var d = j + (config.options.txtCalFirstDay - 0);
if(d > 6) d = d - 7;
cell = createTiddlyElement(row, 'td', null, null, config.macros.calendar.daynames[d]);
if(d == (config.options.txtCalStartOfWeekend-0) || d == (config.options.txtCalStartOfWeekend-0+1))
cell.style.background = config.macros.calendar.weekendbg;
}
}
}
//}}}
//{{{
function createCalendarDays(row, col, first, max, year, mon) {
var i;
if (config.options.chkDisplayWeekNumbers){
if (first<=max) {
var ww = new Date(year,mon,first);
var td=createTiddlyElement(row, 'td');//wn**
var link=createTiddlyLink(td,ww.formatString(config.options.txtWeekNumberLinkFormat),false);
link.appendChild(document.createTextNode(
ww.formatString(config.options.txtWeekNumberDisplayFormat)));
}
else createTiddlyElement(row, 'td');//wn**
}
for(i = 0; i < col; i++)
createTiddlyElement(row, 'td');
var day = first;
for(i = col; i < 7; i++) {
var d = i + (config.options.txtCalFirstDay - 0);
if(d > 6) d = d - 7;
var daycell = createTiddlyElement(row, 'td');
var isaWeekend=((d==(config.options.txtCalStartOfWeekend-0)
|| d==(config.options.txtCalStartOfWeekend-0+1))?true:false);
if(day > 0 && day <= max) {
var celldate = new Date(year, mon, day);
// ELS 10/30/05 - use <<date>> macro's showDate() function to create popup
// ELS 05/29/06 - use journalDateFmt
if (window.showDate) showDate(daycell,celldate,'popup','DD',
config.macros.calendar.journalDateFmt,true, isaWeekend);
else {
if(isaWeekend) daycell.style.background = config.macros.calendar.weekendbg;
var title = celldate.formatString(config.macros.calendar.journalDateFmt);
if(calendarIsHoliday(celldate))
daycell.style.background = config.macros.calendar.holidaybg;
var now=new Date();
if ((now-celldate>=0) && (now-celldate<86400000)) // is today?
daycell.style.background = config.macros.calendar.todaybg;
if(window.findTiddlersWithReminders == null) {
var link = createTiddlyLink(daycell, title, false);
link.appendChild(document.createTextNode(day));
} else
var button = createTiddlyButton(daycell, day, title, onClickCalendarDate);
}
}
day++;
}
}
//}}}
//{{{
// Create a pop-up containing:
// * a link to a tiddler for this date
// * a 'new tiddler' link to add a reminder for this date
// * links to current reminders for this date
// NOTE: this code is only used if [[ReminderMacros]] is installed AND [[DatePlugin]] is //not// installed.
function onClickCalendarDate(ev) { ev=ev||window.event;
var d=new Date(this.getAttribute('title')); var date=d.formatString(config.macros.calendar.journalDateFmt);
var p=Popup.create(this); if (!p) return;
createTiddlyLink(createTiddlyElement(p,'li'),date,true);
var rem='\\n\\<\\<reminder day:%0 month:%1 year:%2 title: \\>\\>';
rem=rem.format([d.getDate(),d.getMonth()+1,d.getYear()+1900]);
var cmd="<<newTiddler label:[[new reminder...]] prompt:[[add a new reminder to '%0']]"
+" title:[[%0]] text:{{store.getTiddlerText('%0','')+'%1'}} tag:%2>>";
wikify(cmd.format([date,rem,config.options.txtCalendarReminderTags]),p);
createTiddlyElement(p,'hr');
var t=findTiddlersWithReminders(d,[0,31],null,1);
for(var i=0; i<t.length; i++) {
var link=createTiddlyLink(createTiddlyElement(p,'li'), t[i].tiddler, false);
link.appendChild(document.createTextNode(t[i]['params']['title']));
}
Popup.show(); ev.cancelBubble=true; if (ev.stopPropagation) ev.stopPropagation(); return false;
}
//}}}
//{{{
function calendarMaxDays(year, mon)
{
var max = config.macros.calendar.monthdays[mon];
if(mon == 1 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) max++;
return max;
}
//}}}
//{{{
function createCalendarDayRows(cal, year, mon)
{
var row = createTiddlyElement(cal, 'tr');
var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first1 < 0) first1 = first1 + 7;
var day1 = -first1 + 1;
var first2 = (new Date(year, mon+1, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first2 < 0) first2 = first2 + 7;
var day2 = -first2 + 1;
var first3 = (new Date(year, mon+2, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first3 < 0) first3 = first3 + 7;
var day3 = -first3 + 1;
var max1 = calendarMaxDays(year, mon);
var max2 = calendarMaxDays(year, mon+1);
var max3 = calendarMaxDays(year, mon+2);
while(day1 <= max1 || day2 <= max2 || day3 <= max3) {
row = createTiddlyElement(cal, 'tr');
createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
createCalendarDays(row, 0, day2, max2, year, mon+1); day2 += 7;
createCalendarDays(row, 0, day3, max3, year, mon+2); day3 += 7;
}
}
//}}}
//{{{
function createCalendarDayRowsSingle(cal, year, mon)
{
var row = createTiddlyElement(cal, 'tr');
var first1 = (new Date(year, mon, 1)).getDay() -1 - (config.options.txtCalFirstDay-0);
if(first1 < 0) first1 = first1+ 7;
var day1 = -first1 + 1;
var max1 = calendarMaxDays(year, mon);
while(day1 <= max1) {
row = createTiddlyElement(cal, 'tr');
createCalendarDays(row, 0, day1, max1, year, mon); day1 += 7;
}
}
//}}}
//{{{
setStylesheet('.calendar, .calendar table, .calendar th, .calendar tr, .calendar td { text-align:center; } .calendar, .calendar a { margin:0px !important; padding:0px !important; }', 'calendarStyles');
//}}}
Yes, you can!
Here's how to do it:
* sign up for a standard tiddlyspot.com site. suppose you called it mytw (accessible at http://mytw.tiddlyspot.com)
* now, open your existing TW (from your hard disk)
* copy the following tiddlers from http://mytw.tiddlyspot.com to your existing TW
** go to backstage, import, and use http://mytw.tiddlyspot.com as the "URL or path name"
** select: ~UploadPlugin and ~TspotSetupPlugin
* save your existing TW (DON'T FORGET THIS STEP)
* reload your existing TW (DON'T FORGET THIS STEP)
* open the ~AdvancedOptions tiddler
** edit Upload Username and Upload Password
Note that we customise the ~SideBarOptions and ~OptionsPanel tiddlers. If you have done your own customisations to either of those tiddlers, you might want to check out the shadow versions and see what you want to include from our changes.
//{{{
//
// Version 1.10:
// - February 25, 2009
// - "master version is in "Han Guk Mu Sool"
//
// Scan the text of the inputTiddler and make various string replacements to "Clean up"
// artifacts from earlier versions of tiddler format standards and image manipulation
// and to improve the handling of image popups from thumbnail sized images.
//
// The main benefit is to avoid the time overhead and errors from manual editing.
//
// Input Parameters:
// * inputTiddlerTitle (required) - name of the tiddler to be scanned
//
// ToDo:
// * run more test scans with additional tiddlers to pick up additional artifacts to be scanned / replaced
//
config.macros.cleanupContentPlugin = {};
config.macros.cleanupContentPlugin.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
//
// Grab the contents of the input tiddler.
//
var inputTiddlerTitle = params.length > 0 ? params[0] : "";
var inputTiddlerObject = store.getTiddler(inputTiddlerTitle);
if (!inputTiddlerObject)
{
wikify("***CleanupNotesPlugin: tiddler (" + inputTiddlerTitle + ") could not be found.***", place);
return;
}
var inputTiddlerText = inputTiddlerObject.text;
var modifiedText = inputTiddlerText;
var inputRegExp, replacementKeyword;
// [1]: before replacing sliders remove the brackets from image tiddlers ie [[image_...]]
inputRegExp = /\[\[(image_[\w\d]+)\]\]/g;
replacementKeyword = "$1";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// [1]: replace sliders for image display with calls to ImagePopupPlugin
// - the capture groups correspond to: $1=cookie $2=imageTiddler $3=buttonText $4=tooltip
var captionPositionFlag = "^";
inputRegExp = /\<\<[\w]+\s([\w]+)\s([\w]+)\s([\w]+)\s("[^"]+")\>\>/g;
replacementKeyword = "<<imagePopupPlugin $2" + " " + captionPositionFlag + " >>";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// [2]: replace old CSS class name usage (ie leftClass is replaced with left)
// - the $1 capture group targets the part of the CSS class name that comes before "Class"
inputRegExp = /\{(\w+)Class\{/g, replacementKeyword = "{$1{";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// [3]: replace old style headings and step numbers
// - 3rd level headings "!!!" to first level "!"
inputRegExp = /\!\!\!/g;
replacementKeyword = "!";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// - "{{stepId{a-z}}}" to "# {{stepId{a-z}}}"
inputRegExp = /(^\{\{stepId\{[a-z]\}\}\})/gi;
replacementKeyword = "# $1 xxx";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// [3]: replace standalone L's and R's. The number of degrees may follow the L or R ie R90 or L360
// - the $1 group targets the single blank, left paren or comma before the "L" or "R"
// - the $2 group targets the single blank, right paren, comma, period, or digit after the "L" or "R"
inputRegExp = /([ \(\,]{1})L([ \)\,\.\d]{1})/g, replacementKeyword = "$1{{left{L}}}$2";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
inputRegExp = /([ \(\,]{1})R([ \)\,\.\d]{1})/g, replacementKeyword = "$1{{right{R}}}$2";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// [4]: replace standalone inconsistent block, punch, or keyword reference with well formed tiddlers. The
// character string regexp is used to minimize errors from cut and pasting since there are so many keywords.
// NOTE - backslashes are escaped with character string regexps
// - $1 group targets the beginning of a string or a single white space, period, comma, or semicolon BEFORE the keyword
// - the second group is a lookahead to matche anything other than a word character or number AFTER the keyword
var group1RepExp = "(^|[\\s\\.\\,\\;]+)";
var group2RegExp = "(?![\\w\\d])";
var modifier = "gi"; // - the "gi" modifier indicates global replace and case insensitive
// blocks: -----------------------------------------------------------------------------------------------------------
keywordRegExp = "High\\s*Block", replacementKeyword = "$1[[High Block]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Inside\\s*To\\s*Outside\\s*Block", replacementKeyword = "$1[[Inside to Outside Block]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Low\\s*Block", replacementKeyword = "$1[[Low Block]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Middle\\s*Block", replacementKeyword = "$1[[Middle Block]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Middle\\s*\\s*Knife\\s*Hand\\s*Block", replacementKeyword = "$1[[Middle Knife Hand Block]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
// kicks: -----------------------------------------------------------------------------------------------------------
keywordRegExp = "Moon[ \\-]In\\s*Kick", replacementKeyword = "$1[[Moon In Kick]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
// punches: -----------------------------------------------------------------------------------------------------------
keywordRegExp = "High\\s*Punch", replacementKeyword = "$1[[High Punch]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Middle\\s*Punch", replacementKeyword = "$1[[Middle Punch]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
// stances: -----------------------------------------------------------------------------------------------------------
keywordRegExp = "Back\\s*Stance", replacementKeyword = "$1[[Back Stance]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Front\\s*Stance", replacementKeyword = "$1[[Front Stance]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
keywordRegExp = "Horse\\s*Stance", replacementKeyword = "$1[[Horse Stance]]";
inputRegExp = new RegExp(group1RepExp + keywordRegExp + group2RegExp, modifier);
modifiedText = modifiedText.replace(inputRegExp, replacementKeyword);
// [5]: Join instances where directions are separated from the number of degrees to turn. What happens
// in effect is that the degrees are moved within the scope of the left or right class.
// do joins for degrees that come after the direction
// - the $1 group targets the "{{left{L" or "{{right{R" strings
// - the $2 group targets the "}}}" string
// - the $3 group targets the training number of degrees e.g., 45|90|135|180|225|270|360
inputRegExp = /(\{\{left\{L)(\}\}\})[\s]*(45|90|135|180|225|270|360)/g, replacementKeyword = "{{left{L $3}}}";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
inputRegExp = /(\{\{right\{R)(\}\}\})[\s]*(45|90|135|180|225|270|360)/g, replacementKeyword = "{{right{R $3}}}";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
// do joins for degrees that preceed the direction
// - the $1 group targets the training number of degrees e.g., 45|90|135|180|225|270|360
// - the $2 group targets the "{{left{L" or "{{right{R" strings
// - the $3 group targets the "}}}" string
inputRegExp = /(45|90|135|180|225|270|360)[\s]*(\{\{left\{L)(\}\}\})/g, replacementKeyword = "{{left{L $1}}}";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
inputRegExp = /(45|90|135|180|225|270|360)[\s]*(\{\{right\{R)(\}\}\})/g, replacementKeyword = "{{right{R $1}}}";
modifiedText = modifiedText.replace(inputRegExp,replacementKeyword);
//
// Lastly: write out the tiddler with the modified text (the output tiddler name is the input tiddler name + "_mod"
//
var outputTiddlerTitle = inputTiddlerTitle + "_mod";
var who = config.options.txtUserName; // current username
var when = new Date(); // current timestamp
var tags=[];
var fields={}; // an empty object
store.saveTiddler(outputTiddlerTitle, outputTiddlerTitle, modifiedText, who, when, tags, fields);
}
//}}}
/***
|Name:|CloseOnCancelPlugin|
|Description:|Closes the tiddler if you click new tiddler then cancel. Default behaviour is to leave it open|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#CloseOnCancelPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.commands.cancelTiddler,{
handler_mptw_orig_closeUnsaved: config.commands.cancelTiddler.handler,
handler: function(event,src,title) {
this.handler_mptw_orig_closeUnsaved(event,src,title);
if (!store.tiddlerExists(title) && !store.isShadowTiddler(title))
story.closeTiddler(title,true);
return false;
}
});
//}}}
@@margin-left:.5em;<<slider chkContents SideBarTabs "contents »" "show
lists of tiddlers contained in this document">>@@
/***
|Name|[[DatePlugin]]|
|Source|http://www.TiddlyTools.com/#DatePlugin|
|Documentation|http://www.TiddlyTools.com/#DatePluginInfo|
|Version|2.7.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|formatted dates plus popup menu with 'journal' link, changes and (optional) reminders|
This plugin provides a general approach to displaying formatted dates and/or links and popups that permit easy navigation and management of tiddlers based on their creation/modification dates.
!!!!!Documentation
>see [[DatePluginInfo]]
!!!!!Configuration
<<<
<<option chkDatePopupHideCreated>> omit 'created' section from date popups
<<option chkDatePopupHideChanged>> omit 'changed' section from date popups
<<option chkDatePopupHideTagged>> omit 'tagged' section from date popups
<<option chkDatePopupHideReminders>> omit 'reminders' section from date popups
<<option chkShowJulianDate>> display Julian day number (1-365) below current date
see [[DatePluginConfig]] for additional configuration settings, for use in calendar displays, including:
*date formats
*color-coded backgrounds
*annual fixed-date holidays
*weekends
<<<
!!!!!Revisions
<<<
2009.05.31 [2.7.1] in addRemindersToPopup(), 'new reminder....' command now uses {{{<<newTiddler>>}}} macro. Also, general code reduction/cleanup.
|please see [[DatePluginInfo]] for additional revision details|
2005.10.30 [0.9.0] pre-release
<<<
!!!!!Code
***/
//{{{
version.extensions.DatePlugin= {major: 2, minor: 7, revision: 1, date: new Date(2009,5,31)};
config.macros.date = {
format: 'YYYY.0MM.0DD', // default date display format
linkformat: 'YYYY.0MM.0DD', // 'dated tiddler' link format
linkedbg: '#babb1e', // 'babble'
todaybg: '#ffab1e', // 'fable'
weekendbg: '#c0c0c0', // 'cocoa'
holidaybg: '#ffaace', // 'face'
createdbg: '#bbeeff', // 'beef'
modifiedsbg: '#bbeeff', // 'beef'
remindersbg: '#c0ffee', // 'coffee'
weekend: [ 1,0,0,0,0,0,1 ], // [ day index values: sun=0, mon=1, tue=2, wed=3, thu=4, fri=5, sat=6 ],
holidays: [ '01/01', '07/04', '07/24', '11/24' ]
// NewYearsDay, IndependenceDay(US), Eric's Birthday (hooray!), Thanksgiving(US)
};
config.macros.date.handler = function(place,macroName,params)
{
// default: display current date
var now =new Date();
var date=now;
var mode='display';
if (params[0]&&['display','popup','link'].contains(params[0].toLowerCase()))
{ mode=params[0]; params.shift(); }
if (!params[0] || params[0]=='today')
{ params.shift(); }
else if (params[0]=='filedate')
{ date=new Date(document.lastModified); params.shift(); }
else if (params[0]=='tiddler')
{ date=store.getTiddler(story.findContainingTiddler(place).id.substr(7)).modified; params.shift(); }
else if (params[0].substr(0,8)=='tiddler:')
{ var t; if ((t=store.getTiddler(params[0].substr(8)))) date=t.modified; params.shift(); }
else {
var y = eval(params.shift().replace(/Y/ig,(now.getYear()<1900)?now.getYear()+1900:now.getYear()));
var m = eval(params.shift().replace(/M/ig,now.getMonth()+1));
var d = eval(params.shift().replace(/D/ig,now.getDate()+0));
date = new Date(y,m-1,d);
}
// date format with optional custom override
var format=this.format; if (params[0]) format=params.shift();
var linkformat=this.linkformat; if (params[0]) linkformat=params.shift();
showDate(place,date,mode,format,linkformat);
}
window.showDate=showDate;
function showDate(place,date,mode,format,linkformat,autostyle,weekend)
{
mode =mode||'display';
format =format||config.macros.date.format;
linkformat=linkformat||config.macros.date.linkformat;
// format the date output
var title=date.formatString(format);
var linkto=date.formatString(linkformat);
// just show the formatted output
if (mode=='display') { place.appendChild(document.createTextNode(title)); return; }
// link to a 'dated tiddler'
var link = createTiddlyLink(place, linkto, false);
link.appendChild(document.createTextNode(title));
link.title = linkto;
link.date = date;
link.format = format;
link.linkformat = linkformat;
// if using a popup menu, replace click handler for dated tiddler link
// with handler for popup and make link text non-italic (i.e., an 'existing link' look)
if (mode=='popup') {
link.onclick = onClickDatePopup;
link.style.fontStyle='normal';
}
// format the popup link to show what kind of info it contains (for use with calendar generators)
if (autostyle) setDateStyle(place,link,weekend);
}
//}}}
//{{{
// NOTE: This function provides default logic for setting the date style when displayed in a calendar
// To customize the date style logic, please see[[DatePluginConfig]]
function setDateStyle(place,link,weekend) {
// alias variable names for code readability
var date=link.date;
var fmt=link.linkformat;
var linkto=date.formatString(fmt);
var cmd=config.macros.date;
if ((weekend!==undefined?weekend:isWeekend(date))&&(cmd.weekendbg!=''))
{ place.style.background = cmd.weekendbg; }
if (hasModifieds(date)||hasCreateds(date)||hasTagged(date,fmt))
{ link.style.fontStyle='normal'; link.style.fontWeight='bold'; }
if (hasReminders(date))
{ link.style.textDecoration='underline'; }
if (isToday(date))
{ link.style.border='1px solid black'; }
if (isHoliday(date)&&(cmd.holidaybg!=''))
{ place.style.background = cmd.holidaybg; }
if (hasCreateds(date)&&(cmd.createdbg!=''))
{ place.style.background = cmd.createdbg; }
if (hasModifieds(date)&&(cmd.modifiedsbg!=''))
{ place.style.background = cmd.modifiedsbg; }
if ((hasTagged(date,fmt)||store.tiddlerExists(linkto))&&(cmd.linkedbg!=''))
{ place.style.background = cmd.linkedbg; }
if (hasReminders(date)&&(cmd.remindersbg!=''))
{ place.style.background = cmd.remindersbg; }
if (isToday(date)&&(cmd.todaybg!=''))
{ place.style.background = cmd.todaybg; }
if (config.options.chkShowJulianDate) { // optional display of Julian date numbers
var m=[0,31,59,90,120,151,181,212,243,273,304,334];
var d=date.getDate()+m[date.getMonth()];
var y=date.getFullYear();
if (date.getMonth()>1 && (y%4==0 && y%100!=0) || y%400==0)
d++; // after February in a leap year
wikify('@@font-size:80%;<br>'+d+'@@',place);
}
}
//}}}
//{{{
function isToday(date) // returns true if date is today
{ var now=new Date(); return ((now-date>=0) && (now-date<86400000)); }
function isWeekend(date) // returns true if date is a weekend
{ return (config.macros.date.weekend[date.getDay()]); }
function isHoliday(date) // returns true if date is a holiday
{
var longHoliday = date.formatString('0MM/0DD/YYYY');
var shortHoliday = date.formatString('0MM/0DD');
for(var i = 0; i < config.macros.date.holidays.length; i++) {
var holiday=config.macros.date.holidays[i];
if (holiday==longHoliday||holiday==shortHoliday) return true;
}
return false;
}
//}}}
//{{{
// Event handler for clicking on a day popup
function onClickDatePopup(e) { e=e||window.event;
var p=Popup.create(this); if (!p) return false;
// always show dated tiddler link (or just date, if readOnly) at the top...
if (!readOnly || store.tiddlerExists(this.date.formatString(this.linkformat)))
createTiddlyLink(createTiddlyElement(p,'li'),this.date.formatString(this.linkformat),true);
else
createTiddlyText(createTiddlyElement(p,'li'),this.date.formatString(this.linkformat));
if (!config.options.chkDatePopupHideCreated)
addCreatedsToPopup(p,this.date,this.format);
if (!config.options.chkDatePopupHideChanged)
addModifiedsToPopup(p,this.date,this.format);
if (!config.options.chkDatePopupHideTagged)
addTaggedToPopup(p,this.date,this.linkformat);
if (!config.options.chkDatePopupHideReminders)
addRemindersToPopup(p,this.date,this.linkformat);
Popup.show(); e.cancelBubble=true; if(e.stopPropagation)e.stopPropagation(); return false;
}
//}}}
//{{{
function indexCreateds() // build list of tiddlers, hash indexed by creation date
{
var createds= { };
var tiddlers = store.getTiddlers('title','excludeLists');
for (var t = 0; t < tiddlers.length; t++) {
var date = tiddlers[t].created.formatString('YYYY0MM0DD')
if (!createds[date])
createds[date]=new Array();
createds[date].push(tiddlers[t].title);
}
return createds;
}
function hasCreateds(date) // returns true if date has created tiddlers
{
if (!config.macros.date.createds) config.macros.date.createds=indexCreateds();
return (config.macros.date.createds[date.formatString('YYYY0MM0DD')]!=undefined);
}
function addCreatedsToPopup(p,when,format)
{
var force=(store.isDirty() && when.formatString('YYYY0MM0DD')==new Date().formatString('YYYY0MM0DD'));
if (force || !config.macros.date.createds) config.macros.date.createds=indexCreateds();
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var createds = config.macros.date.createds[when.formatString('YYYY0MM0DD')];
if (createds) {
createds.sort();
var e=createTiddlyElement(p,'div',null,null,'created ('+createds.length+')');
for(var t=0; t<createds.length; t++) {
var link=createTiddlyLink(createTiddlyElement(p,'li'),createds[t],false);
link.appendChild(document.createTextNode(indent+createds[t]));
}
}
}
//}}}
//{{{
function indexModifieds() // build list of tiddlers, hash indexed by modification date
{
var modifieds= { };
var tiddlers = store.getTiddlers('title','excludeLists');
for (var t = 0; t < tiddlers.length; t++) {
var date = tiddlers[t].modified.formatString('YYYY0MM0DD')
if (!modifieds[date])
modifieds[date]=new Array();
modifieds[date].push(tiddlers[t].title);
}
return modifieds;
}
function hasModifieds(date) // returns true if date has modified tiddlers
{
if (!config.macros.date.modifieds) config.macros.date.modifieds = indexModifieds();
return (config.macros.date.modifieds[date.formatString('YYYY0MM0DD')]!=undefined);
}
function addModifiedsToPopup(p,when,format)
{
var date=when.formatString('YYYY0MM0DD');
var force=(store.isDirty() && date==new Date().formatString('YYYY0MM0DD'));
if (force || !config.macros.date.modifieds) config.macros.date.modifieds=indexModifieds();
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var mods = config.macros.date.modifieds[date];
if (mods) {
// if a tiddler was created on this date, don't list it in the 'changed' section
if (config.macros.date.createds && config.macros.date.createds[date]) {
var temp=[];
for(var t=0; t<mods.length; t++)
if (!config.macros.date.createds[date].contains(mods[t]))
temp.push(mods[t]);
mods=temp;
}
mods.sort();
var e=createTiddlyElement(p,'div',null,null,'changed ('+mods.length+')');
for(var t=0; t<mods.length; t++) {
var link=createTiddlyLink(createTiddlyElement(p,'li'),mods[t],false);
link.appendChild(document.createTextNode(indent+mods[t]));
}
}
}
//}}}
//{{{
function hasTagged(date,format) // returns true if date is tagging other tiddlers
{
return store.getTaggedTiddlers(date.formatString(format)).length>0;
}
function addTaggedToPopup(p,when,format)
{
var indent=String.fromCharCode(160)+String.fromCharCode(160);
var tagged=store.getTaggedTiddlers(when.formatString(format));
if (tagged.length) var e=createTiddlyElement(p,'div',null,null,'tagged ('+tagged.length+')');
for(var t=0; t<tagged.length; t++) {
var link=createTiddlyLink(createTiddlyElement(p,'li'),tagged[t].title,false);
link.appendChild(document.createTextNode(indent+tagged[t].title));
}
}
//}}}
//{{{
function indexReminders(date,leadtime) // build list of tiddlers with reminders, hash indexed by reminder date
{
var reminders = { };
if(window.findTiddlersWithReminders!=undefined) { // reminder plugin is installed
var t = findTiddlersWithReminders(date, [0,leadtime], null, null, 1);
for(var i=0; i<t.length; i++) reminders[t[i].matchedDate]=true;
}
return reminders;
}
function hasReminders(date) // returns true if date has reminders
{
if (window.reminderCacheForCalendar)
return window.reminderCacheForCalendar[date]; // use calendar cache
if (!config.macros.date.reminders)
config.macros.date.reminders = indexReminders(date,90); // create a 90-day leadtime reminder cache
return (config.macros.date.reminders[date]);
}
function addRemindersToPopup(p,when,format)
{
if(window.findTiddlersWithReminders==undefined) return; // reminder plugin not installed
var indent = String.fromCharCode(160)+String.fromCharCode(160);
var reminders=findTiddlersWithReminders(when, [0,31],null,null,1);
createTiddlyElement(p,'div',null,null,'reminders ('+(reminders.length||'none')+')');
for(var t=0; t<reminders.length; t++) {
link = createTiddlyLink(createTiddlyElement(p,'li'),reminders[t].tiddler,false);
var diff=reminders[t].diff;
diff=(diff<1)?'Today':((diff==1)?'Tomorrow':diff+' days');
var txt=(reminders[t].params['title'])?reminders[t].params['title']:reminders[t].tiddler;
link.appendChild(document.createTextNode(indent+diff+' - '+txt));
}
if (readOnly) return; // readonly... omit 'new reminder...' command
var rem='\\<\\<reminder day:%0 month:%1 year:%2 title:"Enter a reminder title here"\\>\\>';
rem=rem.format([when.getDate(),when.getMonth()+1,when.getYear()+1900]);
var cmd="<<newTiddler label:[["+indent+"new reminder...]] prompt:[[add a reminder to '%0']]"
+" title:[[%0]] text:{{var t=store.getTiddlerText('%0','');t+(t.length?'\\n':'')+'%1'}} tag:%2>>";
wikify(cmd.format([when.formatString(format),rem,config.options.txtCalendarReminderTags||'']),
createTiddlyElement(p,'li'));
}
//}}}
/***
|Name:|ExtentTagButtonPlugin|
|Description:|Adds a New tiddler button in the tag drop down|
|Version:|3.2 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#ExtendTagButtonPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
window.onClickTag_mptw_orig = window.onClickTag;
window.onClickTag = function(e) {
window.onClickTag_mptw_orig.apply(this,arguments);
var tag = this.getAttribute("tag");
var title = this.getAttribute("tiddler");
// Thanks Saq, you're a genius :)
var popup = Popup.stack[Popup.stack.length-1].popup;
createTiddlyElement(createTiddlyElement(popup,"li",null,"listBreak"),"div");
wikify("<<newTiddler label:'New tiddler' tag:'"+tag+"'>>",createTiddlyElement(popup,"li"));
return false;
}
//}}}
Welcome to TiddlyWiki!
~TiddlyWiki is a single html file which has all the characteristics of a [[wiki|WikiWikiWeb]] - including all of the content, the functionality (including editing, saving, tagging and searching) and the style sheet. Because it's a single file, it's very portable - you can email it, put it on a web server or share it via a [[USB stick|WikiOnAStick]].
''But it's not just a wiki!'' It has very powerful plugin capabilities, so it can also be used to build new tools. You have full control over how it looks and behaves. For example, ~TiddlyWiki is already being used as:
*A personal notebook
*A GTD ("Getting Things Done") productivity tool
*A collaboration tool
*For building websites (this site is a ~TiddlyWiki file!)
*For rapid prototyping
*...and much more!
You can import and export data to and from all sorts of places. Check out some of the [[Examples]] of ~TiddlyWiki in use, and the [[Features]] that are available.
You can see the web functionality of ~TiddlyWiki by clicking on some of the links on this website. Double click some of the text to see 'edit mode'. For the full range of functions, including editing and saving changes, download and install a copy of the basic version and then follow the guidelines in [[Getting Started|GettingStarted]]. Have fun!
<<tiddler Download>>
/***
|Name:|HideWhenPlugin|
|Description:|Allows conditional inclusion/exclusion in templates|
|Version:|3.1 ($Rev: 3919 $)|
|Date:|$Date: 2008-03-13 02:03:12 +1000 (Thu, 13 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#HideWhenPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{
window.hideWhenLastTest = false;
window.removeElementWhen = function(test,place) {
window.hideWhenLastTest = test;
if (test) {
removeChildren(place);
place.parentNode.removeChild(place);
}
};
merge(config.macros,{
hideWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( eval(paramString), place);
}},
showWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !eval(paramString), place);
}},
hideWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAll(params), place);
}},
showWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAll(params), place);
}},
hideWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAny(params), place);
}},
showWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAny(params), place);
}},
hideWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.tags.containsAll(params), place);
}},
showWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !tiddler.tags.containsAll(params), place);
}},
hideWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0]), place);
}},
showWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !(store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0])), place);
}},
hideWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.title == params[0], place);
}},
showWhenTitleIs: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( tiddler.title != params[0], place);
}},
'else': { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
removeElementWhen( !window.hideWhenLastTest, place);
}}
});
//}}}
! Test the imagePopupPlugin
* <<imagePopupPlugin ImagePopupTestImage >>
! Test the imagesizeplugin
[img(100px,75px)[http://www.hq.nasa.gov/office/pao/History/alsj/a13/ap13-70-HC-291.jpg]]
//{{{
//
// Version 1.6:
// - March 1, 2009:
// - "master version is in "Han Guk Mu Sool"
// - see ImagePopupPluginInfo for documntation
//
// define default styles for CSS classes
setStylesheet(".ippxCaption { color:black; font: 9pt arial, hevetica, sans-serif; font-variant: small-caps; font-weight: bold; text-indent: 0px; list-style-position: inside; margin-bottom: 2 px;}\n.ippCardSize img {max-width: 360px; border: 1px solid gray; padding: 2px; margin: 1px;}\n.ippThumbSize img { max-height: 60px; border: 1px solid yellow; padding: 2px; margin: 1px; }","imagePopupPluginStylesheet");
// add text-indent: 0px; list-style-position: outside;
config.macros.imagePopupPlugin = {};
config.macros.imagePopupPlugin.handler =
function(place,macroName,params,wikifier,paramString,tiddler)
{
// The first parameter is either the name of the tiddler or a direct link to an image
// The second parameter (optional) contains various flags.
var imageString = params.length > 0 ? params[0] : "";
var popupFlags = params.length > 1 ? params[1] : "";
// parse the input flags
var captionPositionFlagRegExp = /\^/; // put caption above image if the flag contains "^"; otherwise below
var directImageLinkFlagRegExp = /dil/i; // imbed image if flag contains "dil"; otherwise imbed tiddler
var embeddedCaptionFlagRegExp = /\_/gi; // image name contains caption if flag contains "_"
var captionOnTop = captionPositionFlagRegExp.test(popupFlags);
var directImageLink = directImageLinkFlagRegExp.test(popupFlags);
var embeddedCaption = embeddedCaptionFlagRegExp.test(popupFlags);
// define fixed parameters for imagepopup
var outputTooltipText = "Click here to show/hide larger image.";
var panelWidth = "380px";
var captionString, imageLink, matchedArray;
var echoMatches = false; // set to true to echo matches to help with debugging
//
// [1] - interpret the firstString as a direct image link to make the popup
// optionally extract the caption from the name of the image
//
if (directImageLink)
{
imageLink = imageString;
captionString = "";
// extract the caption from the imageLink (caption delimited by "_")
if (embeddedCaption)
{
var captionRegExp = /\_([^\.]+)(?=\.\w\w\w$)/;
matchedArray = captionRegExp.exec(imageLink);
captionString = (matchedArray[0]) ? matchedArray[1] : "";
// replace the delimeter "_" with a blank " "
captionString = captionString.replace(embeddedCaptionFlagRegExp," ");
}
buildPopUp(place, panelWidth, imageLink, outputTooltipText, captionString, captionOnTop);
return;
}
//
// [2] - Otherwise interpret the imageString as a name of a tiddler that
// contains the image linkand also contains an optional caption
//
var imageTiddlerObject = store.getTiddler(imageString);
if (!imageTiddlerObject)
{
wikify("Input tiddler (" + imageTiddlerTitle + ") not found", place);
return;
}
var tiddlerText = imageTiddlerObject.text;
var captionString, imageLink, imageTiddler, inputTooltip, matchedArray, matchFound;
var matchedString, resultsListing;
var numberOfMatches = 0;
// here is the default core regular expression for image links (keep unchanged for reference)
// var RefImgRegExp = /\[([<]?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
// var RefClassRegExp = /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{(\n?)/gm
// ok to tinker with these regExp:
// - added "([^\[]*)" at beg and end of regexp to capture prefix and suffix captions if present
// - deleted the global qualifier "g" to match the image strings one at a time
var myImgRegExp = /\[([<]?)(>?)[Ii][Mm][Gg]\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]([^\[]*)/m;
var myClassRegExp = /\{\{[\s]*([\w]+[\s\w]*)[\s]*\{([^\}]+)\}\}\}/gm;
// wikify each instance of an image / caption pair (caption is optional)
while (myImgRegExp.test(tiddlerText))
{
numberOfMatches++;
matchedArray = myImgRegExp.exec(tiddlerText);
matchedString = (matchedArray[0]) ? matchedArray[0] : "";
inputTooltip = (matchedArray[3]) ? matchedArray[3] : "";
imageLink = (matchedArray[4]) ? matchedArray[4] : "";
captionString = (matchedArray[6]) ? matchedArray[6] : "";
// remove any newlines from the caption
captionString = captionString.replace("\n","");
buildPopUp(place, panelWidth, imageLink, outputTooltipText, captionString, captionOnTop);
// "consume" the matchedString by replacing it with "" (empty string);
tiddlerText = tiddlerText.replace(matchedString,"");
// summarize results for this pass
resultsListing = "\n\nmatchedString (numberOfMatches="+numberOfMatches+"):" + "{{{" + matchedString + "}}}"
+ "\ninputTooltip:" + "{{{" + inputTooltip + "}}}"
+ "\nimageLink:" + "{{{" + imageLink + "}}}"
+ "\ncaption:" + "{{{" + captionString + "}}}";
if (echoMatches) {wikify(resultsListing, place);}
}
}
//
// Build the popup string to be wikified using the nextedSlidersPlugin.
//
function buildPopUp(place, panelWidth, imageLink, outputTooltipText, captionString, captionOnTop)
{
// Two strings are built one with caption on top and the other with caption on bottom.
var topCaptionString = "+++^" + panelWidth + "^*{{ippThumbSize{[<img src=" + imageLink + ">|"
+ outputTooltipText + "]}}}{{ippCaption{" + captionString + "}}}\n{{ippCardSize{[img["
+ imageLink + "]]}}}===";
var bottomCaptionString = "+++^" + panelWidth + "^*{{ippThumbSize{[<img src=" + imageLink
+ ">|" + outputTooltipText + "]}}}{{ippCardSize{[img[" + imageLink
+ "]]}}}\n{{ippCaption{" + captionString + "}}}===";
// The captionOnTop flag determines which caption string to use.
var popupString = (captionOnTop) ? topCaptionString : bottomCaptionString;
wikify(popupString, place);
}
//}}}
[img[imagetooltip|http://www.hq.nasa.gov/office/pao/History/alsj/a13/ap13-70-HC-291.jpg]]
"Apollo 13 bathed in floodlight during early-morning rollout. 16 December 1969.
/***
|Name|ImageSizePlugin|
|Source|http://www.TiddlyTools.com/#ImageSizePlugin|
|Version|1.2.1|
|Author|Eric Shulman|
|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,formatter|
|Requires||
|Overrides|'image' formatter|
|Description|adds support for resizing images|
This plugin adds optional syntax to scale an image to a specified width and height and/or interactively resize the image with the mouse.
!!!!!Usage
<<<
The extended image syntax is:
{{{
[img(w+,h+)[...][...]]
}}}
where ''(w,h)'' indicates the desired width and height (in CSS units, e.g., px, em, cm, in, or %). Use ''auto'' (or a blank value) for either dimension to scale that dimension proportionally (i.e., maintain the aspect ratio). You can also calculate a CSS value 'on-the-fly' by using a //javascript expression// enclosed between """{{""" and """}}""". Appending a plus sign (+) to a dimension enables interactive resizing in that dimension (by dragging the mouse inside the image). Use ~SHIFT-click to show the full-sized (un-scaled) image. Use ~CTRL-click to restore the starting size (either scaled or full-sized).
<<<
!!!!!Examples
<<<
{{{
[img(100px+,75px+)[images/meow2.jpg]]
}}}
[img(100px+,75px+)[images/meow2.jpg]]
{{{
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img( 1%+,+)[images/meow.gif]]
}}}
[<img(34%+,+)[images/meow.gif]]
[<img(21% ,+)[images/meow.gif]]
[<img(13%+, )[images/meow.gif]]
[<img( 8%+, )[images/meow.gif]]
[<img( 5% , )[images/meow.gif]]
[<img( 3% , )[images/meow.gif]]
[<img( 2% , )[images/meow.gif]]
[img( 1%+,+)[images/meow.gif]]
{{tagClear{
}}}
<<<
!!!!!Revisions
<<<
2009.02.24 [1.2.1] cleanup width/height regexp, use '+' suffix for resizing
2009.02.22 [1.2.0] added stretchable images
2008.01.19 [1.1.0] added evaluated width/height values
2008.01.18 [1.0.1] regexp for "(width,height)" now passes all CSS values to browser for validation
2008.01.17 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImageSizePlugin= {major: 1, minor: 2, revision: 1, date: new Date(2009,2,24)};
//}}}
//{{{
var f=config.formatters[config.formatters.findByField("name","image")];
f.match="\\[[<>]?[Ii][Mm][Gg](?:\\([^,]*,[^\\)]*\\))?\\[";
f.lookaheadRegExp=/\[([<]?)(>?)[Ii][Mm][Gg](?:\(([^,]*),([^\)]*)\))?\[(?:([^\|\]]+)\|)?([^\[\]\|]+)\](?:\[([^\]]*)\])?\]/mg;
f.handler=function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var floatLeft=lookaheadMatch[1];
var floatRight=lookaheadMatch[2];
var width=lookaheadMatch[3];
var height=lookaheadMatch[4];
var tooltip=lookaheadMatch[5];
var src=lookaheadMatch[6];
var link=lookaheadMatch[7];
// Simple bracketted link
var e = w.output;
if(link) { // LINKED IMAGE
if (config.formatterHelpers.isExternalLink(link)) {
if (config.macros.attach && config.macros.attach.isAttachment(link)) {
// see [[AttachFilePluginFormatters]]
e = createExternalLink(w.output,link);
e.href=config.macros.attach.getAttachment(link);
e.title = config.macros.attach.linkTooltip + link;
} else
e = createExternalLink(w.output,link);
} else
e = createTiddlyLink(w.output,link,false,null,w.isStatic);
addClass(e,"imageLink");
}
var img = createTiddlyElement(e,"img");
if(floatLeft) img.align="left"; else if(floatRight) img.align="right";
if(width||height) {
var x=width.trim(); var y=height.trim();
var stretchW=(x.substr(x.length-1,1)=='+'); if (stretchW) x=x.substr(0,x.length-1);
var stretchH=(y.substr(y.length-1,1)=='+'); if (stretchH) y=y.substr(0,y.length-1);
if (x.substr(0,2)=="{{")
{ try{x=eval(x.substr(2,x.length-4))} catch(e){displayMessage(e.description||e.toString())} }
if (y.substr(0,2)=="{{")
{ try{y=eval(y.substr(2,y.length-4))} catch(e){displayMessage(e.description||e.toString())} }
img.style.width=x.trim(); img.style.height=y.trim();
config.formatterHelpers.addStretchHandlers(img,stretchW,stretchH);
}
if(tooltip) img.title = tooltip;
// GET IMAGE SOURCE
if (config.macros.attach && config.macros.attach.isAttachment(src))
src=config.macros.attach.getAttachment(src); // see [[AttachFilePluginFormatters]]
else if (config.formatterHelpers.resolvePath) { // see [[ImagePathPlugin]]
if (config.browser.isIE || config.browser.isSafari) {
img.onerror=(function(){
this.src=config.formatterHelpers.resolvePath(this.src,false);
return false;
});
} else
src=config.formatterHelpers.resolvePath(src,true);
}
img.src=src;
w.nextMatch = this.lookaheadRegExp.lastIndex;
}
}
config.formatterHelpers.addStretchHandlers=function(e,stretchW,stretchH) {
e.title=((stretchW||stretchH)?'DRAG=stretch/shrink, ':'')
+'SHIFT-CLICK=show full size, CTRL-CLICK=restore initial size';
e.statusMsg='width=%0, height=%1';
e.style.cursor='move';
e.originalW=e.style.width;
e.originalH=e.style.height;
e.minW=Math.max(e.offsetWidth/20,10);
e.minH=Math.max(e.offsetHeight/20,10);
e.stretchW=stretchW;
e.stretchH=stretchH;
e.onmousedown=function(ev) { var ev=ev||window.event;
this.sizing=true;
this.startX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
this.startY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
this.startW=this.offsetWidth;
this.startH=this.offsetHeight;
return false;
};
e.onmousemove=function(ev) { var ev=ev||window.event;
if (this.sizing) {
var s=this.style;
var currX=!config.browser.isIE?ev.pageX:(ev.clientX+findScrollX());
var currY=!config.browser.isIE?ev.pageY:(ev.clientY+findScrollY());
var newW=(currX-this.offsetLeft)/(this.startX-this.offsetLeft)*this.startW;
var newH=(currY-this.offsetTop )/(this.startY-this.offsetTop )*this.startH;
if (this.stretchW) s.width =Math.floor(Math.max(newW,this.minW))+'px';
if (this.stretchH) s.height=Math.floor(Math.max(newH,this.minH))+'px';
clearMessage(); displayMessage(this.statusMsg.format([s.width,s.height]));
}
return false;
};
e.onmouseup=function(ev) { var ev=ev||window.event;
if (ev.shiftKey) { this.style.width=this.style.height=''; }
if (ev.ctrlKey) { this.style.width=this.originalW; this.style.height=this.originalH; }
this.sizing=false;
clearMessage();
return false;
};
e.onmouseout=function(ev) { var ev=ev||window.event;
this.sizing=false;
clearMessage();
return false;
};
}
//}}}
/***
|Name|ImportTiddlersPlugin|
|Source|http://www.TiddlyTools.com/#ImportTiddlersPlugin|
|Documentation|http://www.TiddlyTools.com/#ImportTiddlersPluginInfo|
|Version|4.5.1|
|Author|Eric Shulman|
|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|config.macros.importTiddlers.handler|
|Description|interactive controls for import/export with filtering.|
Combine tiddlers from any two TiddlyWiki documents. An interactive control panel lets you pick a source document and import selected tiddlers, with prompting for skip, rename, merge or replace actions when importing tiddlers that match existing titles. Generates a detailed report of import 'history' in ImportedTiddlers.
!!!!!Documentation
<<<
see [[ImportTiddlersPluginInfo]] for details
<<<
!!!!!interactive control panel:
<<<
<<importTiddlers inline>>
{{clear{
^^(see also: [[ImportTiddlers]] shadow tiddler)^^}}}
<<<
!!!!!Revisions
<<<
2009.07.03 [4.5.1] fixups for TW252: doHttp() doesn't return XHR and convertUTF8ToUnicode() not needed for local I/O
2009.05.04 [4.5.0] import from CSV-formatted files
|please see [[ImportTiddlersPluginInfo]] for additional revision details|
2005.07.20 [1.0.0] Initial Release
<<<
!!!!!Code
***/
//{{{
version.extensions.ImportTiddlersPlugin= {major: 4, minor: 5, revision: 1, date: new Date(2009,7,3)};
// IE needs explicit global scoping for functions/vars called from browser events
window.onClickImportButton=onClickImportButton;
window.refreshImportList=refreshImportList;
// default cookie/option values
if (!config.options.chkImportReport) config.options.chkImportReport=true;
// default shadow definition
config.shadowTiddlers.ImportTiddlers='<<importTiddlers inline>>';
// use shadow tiddler content in backstage panel
if (config.tasks) config.tasks.importTask.content='<<tiddler ImportTiddlers>>' // TW2.2 or above
//}}}
//{{{
// backward-compatiblity for TW2.0.x and TW1.2.x
if (config.macros.importTiddlers==undefined) config.macros.importTiddlers={};
if (typeof merge=='undefined') {
function merge(dst,src,preserveExisting) {
for(var i in src) { if(!preserveExisting || dst[i] === undefined) dst[i] = src[i]; }
return dst;
}
}
if (config.browser.isGecko===undefined)
config.browser.isGecko=(config.userAgent.indexOf('gecko')!=-1);
//}}}
//{{{
merge(config.macros.importTiddlers,{
$: function(id) { return document.getElementById(id); }, // abbreviation
label: 'import tiddlers',
prompt: 'Copy tiddlers from another document',
openMsg: 'Opening %0',
openErrMsg: 'Could not open %0 - error=%1',
readMsg: 'Read %0 bytes from %1',
foundMsg: 'Found %0 tiddlers in %1',
filterMsg: "Filtered %0 tiddlers matching '%1'",
summaryMsg: '%0 tiddler%1 in the list',
summaryFilteredMsg: '%0 of %1 tiddler%2 in the list',
plural: 's are',
single: ' is',
countMsg: '%0 tiddlers selected for import',
processedMsg: 'Processed %0 tiddlers',
importedMsg: 'Imported %0 of %1 tiddlers from %2',
loadText: 'please load a document...',
closeText: 'close',
doneText: 'done',
startText: 'import',
stopText: 'stop',
local: true, // default to import from local file
src: '', // path/filename or URL of document to import (retrieved from SiteUrl)
proxy: '', // URL for remote proxy script (retrieved from SiteProxy)
useProxy: false, // use specific proxy script in front of remote URL
inbound: null, // hash-indexed array of tiddlers from other document
newTags: '', // text of tags added to imported tiddlers
addTags: true, // add new tags to imported tiddlers
listsize: 10, // # of lines to show in imported tiddler list
importTags: true, // include tags from remote source document when importing a tiddler
keepTags: true, // retain existing tags when replacing a tiddler
sync: false, // add 'server' fields to imported tiddlers (for sync function)
lastFilter: '', // most recent filter (URL hash) applied
lastAction: null, // most recent collision button performed
index: 0, // current processing index in import list
sort: '' // sort order for imported tiddler listbox
});
//}}}
//{{{
// hijack core macro handler
if (config.macros.importTiddlers.coreHandler==undefined)
config.macros.importTiddlers.coreHandler=config.macros.importTiddlers.handler;
config.macros.importTiddlers.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
if (!params[0] || params[0].toLowerCase()=='core') { // default to built in
if (config.macros.importTiddlers.coreHandler)
config.macros.importTiddlers.coreHandler.apply(this,arguments);
else
createTiddlyButton(place,this.label,this.prompt,onClickImportMenu);
} else if (params[0]=='link') { // show link to floating panel
createTiddlyButton(place,params[1]||this.label,params[2]||this.prompt,onClickImportMenu);
} else if (params[0]=='inline') {// show panel as INLINE tiddler content
createImportPanel(place);
this.$('importPanel').style.position='static';
this.$('importPanel').style.display='block';
} else if (config.macros.loadTiddlers)
config.macros.loadTiddlers.handler(place,macroName,params); // any other params: loadtiddlers
}
//}}}
//{{{
// Handle link click to create/show/hide control panel
function onClickImportMenu(e) { var e=e||window.event;
var parent=resolveTarget(e).parentNode;
var panel=document.getElementById('importPanel');
if (panel==undefined || panel.parentNode!=parent) panel=createImportPanel(parent);
var isOpen=panel.style.display=='block';
if(config.options.chkAnimate)
anim.startAnimating(new Slider(panel,!isOpen,false,'none'));
else
panel.style.display=isOpen?'none':'block';
e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); return(false);
}
//}}}
//{{{
// Create control panel: HTML, CSS
function createImportPanel(place) {
var cmi=config.macros.importTiddlers; // abbrev
var panel=cmi.$('importPanel');
if (panel) { panel.parentNode.removeChild(panel); }
setStylesheet(cmi.css,'importTiddlers');
panel=createTiddlyElement(place,'span','importPanel',null,null)
panel.innerHTML=cmi.html;
refreshImportList();
var siteURL=store.getTiddlerText('SiteUrl'); if (!siteURL) siteURL='';
cmi.$('importSourceURL').value=siteURL;
cmi.src=siteURL;
var siteProxy=store.getTiddlerText('SiteProxy'); if (!siteProxy) siteProxy='SiteProxy';
cmi.$('importSiteProxy').value=siteProxy;
cmi.proxy=siteProxy;
if (config.browser.isGecko) { // FF3 FIXUP
cmi.$('fileImportSource').style.display='none';
cmi.$('importLocalPanelFix').style.display='block';
}
cmi.$('chkSync').checked=cmi.sync;
cmi.$('chkImportTags').checked=cmi.importTags;
cmi.$('chkKeepTags').checked=cmi.keepTags;
cmi.$('chkAddTags').checked=cmi.addTags;
cmi.$('txtNewTags').value=cmi.newTags;
cmi.$('txtNewTags').style.display=cmi.addTags?'block':'none';
cmi.$('chkSync').checked=cmi.sync;
cmi.$('chkImportReport').checked=config.options.chkImportReport;
return panel;
}
//}}}
//{{{
config.macros.importTiddlers.css = '\
#importPanel {\
display: none; position:absolute; z-index:11; width:35em; right:105%; top:3em;\
background-color: #eee; color:#000; font-size: 8pt; line-height:110%;\
border:1px solid black; border-bottom-width: 3px; border-right-width: 3px;\
padding: 0.5em; margin:0em; -moz-border-radius:1em;-webkit-border-radius:1em;\
}\
#importPanel a, #importPanel td a { color:#009; display:inline; margin:0px; padding:1px; }\
#importPanel table { width:100%; border:0px; padding:0px; margin:0px; font-size:8pt; line-height:110%; background:transparent; }\
#importPanel tr { border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel td { color:#000; border:0px;padding:0px;margin:0px; background:transparent; }\
#importPanel select { width:100%;margin:0px;font-size:8pt;line-height:110%;}\
#importPanel input { width:98%;padding:0px;margin:0px;font-size:8pt;line-height:110%}\
#importPanel .box { border:1px solid #000; background-color:#eee; padding:3px 5px; margin-bottom:5px; -moz-border-radius:5px;-webkit-border-radius:5px;}\
#importPanel .topline { border-top:1px solid #999; padding-top:2px; margin-top:2px; }\
#importPanel .rad { width:auto; }\
#importPanel .chk { width:auto; margin:1px;border:0; }\
#importPanel .btn { width:auto; }\
#importPanel .btn1 { width:98%; }\
#importPanel .btn2 { width:48%; }\
#importPanel .btn3 { width:32%; }\
#importPanel .btn4 { width:23%; }\
#importPanel .btn5 { width:19%; }\
#importPanel .importButton { padding: 0em; margin: 0px; font-size:8pt; }\
#importPanel .importListButton { padding:0em 0.25em 0em 0.25em; color: #000000; display:inline }\
#backstagePanel #importPanel { left:10%; right:auto; }\
';
//}}}
//{{{
config.macros.importTiddlers.html = '\
<!-- source and report -->\
<table><tr><td align=left>\
import from\
<input type="radio" class="rad" name="importFrom" id="importFromFile" value="file" CHECKED\
onclick="onClickImportButton(this,event)" title="show file controls"> local file\
<input type="radio" class="rad" name="importFrom" id="importFromWeb" value="http"\
onclick="onClickImportButton(this,event)" title="show web controls"> web server\
</td><td align=right>\
<input type=checkbox class="chk" id="chkImportReport"\
onClick="config.options[\'chkImportReport\']=this.checked;"> create report\
</td></tr></table>\
\
<div class="box" id="importSourcePanel" style="margin:.5em">\
<div id="importLocalPanel" style="display:block;margin-bottom:2px;"><!-- import from local file -->\
enter or browse for source path/filename<br>\
<input type="file" id="fileImportSource" size=57 style="width:100%"\
onKeyUp="config.macros.importTiddlers.src=this.value"\
onChange="config.macros.importTiddlers.src=this.value;document.getElementById(\'importLoad\').onclick()">\
<div id="importLocalPanelFix" style="display:none"><!-- FF3 FIXUP -->\
<input type="text" id="fileImportSourceFix" style="width:90%"\
title="Enter a path/file to import"\
onKeyUp="config.macros.importTiddlers.src=this.value"\
onChange="config.macros.importTiddlers.src=this.value;document.getElementById(\'importLoad\').onclick()">\
<input type="button" id="fileImportSourceFixButton" style="width:7%" value="..."\
title="Select a path/file to import"\
onClick="var r=config.macros.importTiddlers.askForFilename(this); if (!r||!r.length) return;\
document.getElementById(\'fileImportSourceFix\').value=r;\
config.macros.importTiddlers.src=r;\
document.getElementById(\'importLoad\').onclick()">\
</div><!--end FF3 FIXUP-->\
</div><!--end local-->\
<div id="importHTTPPanel" style="display:none;margin-bottom:2px;"><!-- import from http server -->\
<table><tr><td align=left>\
enter a URL or <a href="javascript:;" id="importSelectFeed"\
onclick="onClickImportButton(this,event)" title="select a pre-defined \'systemServer\' URL">\
select a server</a><br>\
</td><td align=right>\
<input type="checkbox" class="chk" id="importUsePassword"\
onClick="config.macros.importTiddlers.usePassword=this.checked;\
config.macros.importTiddlers.showPanel(\'importIDPWPanel\',this.checked,true);">password\
<input type="checkbox" class="chk" id="importUseProxy"\
onClick="config.macros.importTiddlers.useProxy=this.checked;\
config.macros.importTiddlers.showPanel(\'importSiteProxy\',this.checked,true);">proxy\
</td></tr></table>\
<input type="text" id="importSiteProxy" style="display:none;margin-bottom:1px" onfocus="this.select()" value="SiteProxy"\
onKeyUp="config.macros.importTiddlers.proxy=this.value"\
onChange="config.macros.importTiddlers.proxy=this.value;">\
<input type="text" id="importSourceURL" onfocus="this.select()" value="SiteUrl"\
onKeyUp="config.macros.importTiddlers.src=this.value"\
onChange="config.macros.importTiddlers.src=this.value;">\
<div id="importIDPWPanel" style="text-align:center;margin-top:2px;display:none";>\
username: <input type=text id="txtImportID" style="width:25%" \
onChange="config.options.txtRemoteUsername=this.value;">\
password: <input type=password id="txtImportPW" style="width:25%" \
onChange="config.options.txtRemotePassword=this.value;">\
</div><!--end idpw-->\
</div><!--end http-->\
</div><!--end source-->\
\
<div class="box" id="importSelectPanel" style="display:none;margin:.5em;">\
<table><tr><td align=left>\
select:\
<a href="javascript:;" id="importSelectAll"\
onclick="onClickImportButton(this);return false;" title="SELECT all tiddlers">\
all</a>\
<a href="javascript:;" id="importSelectNew"\
onclick="onClickImportButton(this);return false;" title="SELECT tiddlers not already in destination document">\
added</a>\
<a href="javascript:;" id="importSelectChanges"\
onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been updated in source document">\
changes</a>\
<a href="javascript:;" id="importSelectDifferences"\
onclick="onClickImportButton(this);return false;" title="SELECT tiddlers that have been added or are different from existing tiddlers">\
differences</a>\
</td><td align=right>\
<a href="javascript:;" id="importListSmaller"\
onclick="onClickImportButton(this);return false;" title="SHRINK list size">\
– </a>\
<a href="javascript:;" id="importListLarger"\
onclick="onClickImportButton(this);return false;" title="GROW list size">\
+ </a>\
<a href="javascript:;" id="importListMaximize"\
onclick="onClickImportButton(this);return false;" title="MAXIMIZE/RESTORE list size">\
= </a>\
</td></tr></table>\
<select id="importList" size=8 multiple\
onchange="setTimeout(\'refreshImportList(\'+this.selectedIndex+\')\',1)">\
<!-- NOTE: delay refresh so list is updated AFTER onchange event is handled -->\
</select>\
<div style="text-align:center">\
<a href="javascript:;"\
title="click for help using filters..."\
onclick="alert(\'A filter consists of one or more space-separated combinations of:\\n\\ntiddler titles\\ntag:[[tagvalue]]\\ntag:[[tag expression]] (requires MatchTagsPlugin)\\nstory:[[TiddlerName]]\\nsearch:[[searchtext]]\\n\\nUse a blank filter for all tiddlers.\')"\
>filter</a>\
<input type="text" id="importLastFilter" style="margin-bottom:1px; width:65%"\
title="Enter a combination of one or more filters. Use a blank filter for all tiddlers."\
onfocus="this.select()" value=""\
onKeyUp="config.macros.importTiddlers.lastFilter=this.value"\
onChange="config.macros.importTiddlers.lastFilter=this.value;">\
<input type="button" id="importApplyFilter" style="width:20%" value="apply"\
title="filter list of tiddlers to include only those that match certain criteria"\
onclick="onClickImportButton(this)">\
</div>\
</div><!--end select-->\
\
<div class="box" id="importOptionsPanel" style="text-align:center;margin:.5em;display:none;">\
apply tags: <input type=checkbox class="chk" id="chkImportTags" checked\
onClick="config.macros.importTiddlers.importTags=this.checked;">from source \
<input type=checkbox class="chk" id="chkKeepTags" checked\
onClick="config.macros.importTiddlers.keepTags=this.checked;">keep existing \
<input type=checkbox class="chk" id="chkAddTags" \
onClick="config.macros.importTiddlers.addTags=this.checked;\
config.macros.importTiddlers.showPanel(\'txtNewTags\',this.checked,false);\
if (this.checked) document.getElementById(\'txtNewTags\').focus();">add tags<br>\
<input type=text id="txtNewTags" style="margin-top:4px;display:none;" size=15\ onfocus="this.select()" \
title="enter tags to be added to imported tiddlers" \
onKeyUp="config.macros.importTiddlers.newTags=this.value;\
document.getElementById(\'chkAddTags\').checked=this.value.length>0;" autocomplete=off>\
<nobr><input type=checkbox class="chk" id="chkSync" \
onClick="config.macros.importTiddlers.sync=this.checked;">\
link tiddlers to source document (for sync later)</nobr>\
</div><!--end options-->\
\
<div id="importButtonPanel" style="text-align:center">\
<input type=button id="importLoad" class="importButton btn3" value="open"\
title="load listbox with tiddlers from source document"\
onclick="onClickImportButton(this)">\
<input type=button id="importOptions" class="importButton btn3" value="options..."\
title="set options for tags, sync, etc."\
onclick="onClickImportButton(this)">\
<input type=button id="importStart" class="importButton btn3" value="import"\
title="start/stop import of selected source tiddlers into current document"\
onclick="onClickImportButton(this)">\
<input type=button id="importClose" class="importButton btn3" value="done"\
title="clear listbox or hide control panel"\
onclick="onClickImportButton(this)">\
</div>\
\
<div class="none" id="importCollisionPanel" style="display:none;margin:.5em 0 .5em .5em;">\
<table><tr><td style="width:65%" align="left">\
<table><tr><td align=left>\
tiddler already exists:\
</td><td align=right>\
<input type=checkbox class="chk" id="importApplyToAll" \
onclick="document.getElementById(\'importRename\').disabled=this.checked;"\
checked>apply to all\
</td></tr></table>\
<input type=text id="importNewTitle" size=15 autocomplete=off">\
</td><td style="width:34%" align="center">\
<input type=button id="importMerge"\
class="importButton" style="width:47%" value="merge"\
title="append the incoming tiddler to the existing tiddler"\
onclick="onClickImportButton(this)"><!--\
--><input type=button id="importSkip"\
class="importButton" style="width:47%" value="skip"\
title="do not import this tiddler"\
onclick="onClickImportButton(this)"><!--\
--><br><input type=button id="importRename"\
class="importButton" style="width:47%" value="rename"\
title="rename the incoming tiddler"\
onclick="onClickImportButton(this)"><!--\
--><input type=button id="importReplace"\
class="importButton" style="width:47%" value="replace"\
title="discard the existing tiddler"\
onclick="onClickImportButton(this)">\
</td></tr></table>\
</div><!--end collision-->\
';
//}}}
//{{{
// process control interactions
function onClickImportButton(which,event) {
var cmi=config.macros.importTiddlers; // abbreviation
var list=cmi.$('importList'); if (!list) return;
var thePanel=cmi.$('importPanel');
var theCollisionPanel=cmi.$('importCollisionPanel');
var theNewTitle=cmi.$('importNewTitle');
var count=0;
switch (which.id)
{
case 'importFromFile': // show local panel
case 'importFromWeb': // show HTTP panel
cmi.local=(which.id=='importFromFile');
cmi.showPanel('importLocalPanel',cmi.local);
cmi.showPanel('importHTTPPanel',!cmi.local);
break;
case 'importOptions': // show/hide options panel
cmi.showPanel('importOptionsPanel',cmi.$('importOptionsPanel').style.display=='none');
break;
case 'fileImportSource':
case 'importLoad': // load import source into hidden frame
importReport(); // if an import was in progress, generate a report
cmi.inbound=null; // clear the imported tiddler buffer
refreshImportList(); // reset/resize the listbox
if (cmi.src=='') break;
// Load document, read it's DOM and fill the list
cmi.loadRemoteFile(cmi.src,cmi.filterTiddlerList);
break;
case 'importSelectFeed': // select a pre-defined systemServer feed URL
var p=Popup.create(which); if (!p) return;
var tids=store.getTaggedTiddlers('systemServer');
if (!tids.length)
createTiddlyText(createTiddlyElement(p,'li'),'no pre-defined server feeds');
for (var t=0; t<tids.length; t++) {
var u=store.getTiddlerSlice(tids[t].title,'URL');
var d=store.getTiddlerSlice(tids[t].title,'Description');
if (!d||!d.length) d=store.getTiddlerSlice(tids[t].title,'description');
if (!d||!d.length) d=u;
createTiddlyButton(createTiddlyElement(p,'li'),tids[t].title,d,
function(){
var u=this.getAttribute('url');
document.getElementById('importSourceURL').value=u;
config.macros.importTiddlers.src=u;
document.getElementById('importLoad').onclick();
},
null,null,null,{url:u});
}
Popup.show();
event.cancelBubble = true;
if (event.stopPropagation) event.stopPropagation();
return(false);
// create popup with feed list
// onselect, insert feed URL into input field.
break;
case 'importSelectAll': // select all tiddler list items (i.e., not headings)
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
if (list.options[t].value=='') continue;
list.options[t].selected=true;
count++;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importSelectNew': // select tiddlers not in current document
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
list.options[t].selected=false;
if (list.options[t].value=='') continue;
list.options[t].selected=!store.tiddlerExists(list.options[t].value);
count+=list.options[t].selected?1:0;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importSelectChanges': // select tiddlers that are updated from existing tiddlers
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
list.options[t].selected=false;
if (list.options[t].value==''||!store.tiddlerExists(list.options[t].value)) continue;
for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified>0); // updated tiddler
count+=list.options[t].selected?1:0;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importSelectDifferences': // select tiddlers that are new or different from existing tiddlers
importReport(); // if an import was in progress, generate a report
for (var t=0,count=0; t < list.options.length; t++) {
list.options[t].selected=false;
if (list.options[t].value=='') continue;
if (!store.tiddlerExists(list.options[t].value)) { list.options[t].selected=true; count++; continue; }
for (var i=0; i<cmi.inbound.length; i++) // find matching inbound tiddler
{ var inbound=cmi.inbound[i]; if (inbound.title==list.options[t].value) break; }
list.options[t].selected=(inbound.modified-store.getTiddler(list.options[t].value).modified!=0); // changed tiddler
count+=list.options[t].selected?1:0;
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
cmi.$('importStart').disabled=!count;
break;
case 'importApplyFilter': // filter list to include only matching tiddlers
importReport(); // if an import was in progress, generate a report
clearMessage();
if (!cmi.all) // no tiddlers loaded = '0 selected'
{ displayMessage(cmi.countMsg.format([0])); return false; }
var hash=cmi.$('importLastFilter').value;
cmi.inbound=cmi.filterByHash('#'+hash,cmi.all);
refreshImportList(); // reset/resize the listbox
break;
case 'importStart': // initiate the import processing
importReport(); // if an import was in progress, generate a report
cmi.$('importApplyToAll').checked=false;
cmi.$('importStart').value=cmi.stopText;
if (cmi.index>0) cmi.index=-1; // stop processing
else cmi.index=importTiddlers(0); // or begin processing
importStopped();
break;
case 'importClose': // unload imported tiddlers or hide the import control panel
// if imported tiddlers not loaded, close the import control panel
if (!cmi.inbound) { thePanel.style.display='none'; break; }
importReport(); // if an import was in progress, generate a report
cmi.inbound=null; // clear the imported tiddler buffer
refreshImportList(); // reset/resize the listbox
break;
case 'importSkip': // don't import the tiddler
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
theImported.status='skipped after asking'; // mark item as skipped
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index+1); // resume with NEXT item
importStopped();
break;
case 'importRename': // change name of imported tiddler
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
theImported.status = 'renamed from '+theImported.title; // mark item as renamed
theImported.set(theNewTitle.value,null,null,null,null); // change the tiddler title
theItem.value = theNewTitle.value; // change the listbox item text
theItem.text = theNewTitle.value; // change the listbox item text
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index); // resume with THIS item
importStopped();
break;
case 'importMerge': // join existing and imported tiddler content
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
var theExisting = store.getTiddler(theItem.value);
var theText = theExisting.text+'\n----\n^^merged from: ';
theText +='[['+cmi.src+'#'+theItem.value+'|'+cmi.src+'#'+theItem.value+']]^^\n';
theText +='^^'+theImported.modified.toLocaleString()+' by '+theImported.modifier+'^^\n'+theImported.text;
var theDate = new Date();
var theTags = theExisting.getTags()+' '+theImported.getTags();
theImported.set(null,theText,null,theDate,theTags);
theImported.status = 'merged with '+theExisting.title; // mark item as merged
theImported.status += ' - '+theExisting.modified.formatString('MM/DD/YYYY 0hh:0mm:0ss');
theImported.status += ' by '+theExisting.modifier;
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index); // resume with this item
importStopped();
break;
case 'importReplace': // substitute imported tiddler for existing tiddler
cmi.lastAction=which;
var theItem = list.options[cmi.index];
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==theItem.value) break;
var theImported = cmi.inbound[j];
var theExisting = store.getTiddler(theItem.value);
theImported.status = 'replaces '+theExisting.title; // mark item for replace
theImported.status += ' - '+theExisting.modified.formatString('MM/DD/YYYY 0hh:0mm:0ss');
theImported.status += ' by '+theExisting.modifier;
theCollisionPanel.style.display='none';
cmi.index=importTiddlers(cmi.index); // resume with THIS item
importStopped();
break;
case 'importListSmaller': // decrease current listbox size, minimum=5
if (list.options.length==1) break;
list.size-=(list.size>5)?1:0;
cmi.listsize=list.size;
break;
case 'importListLarger': // increase current listbox size, maximum=number of items in list
if (list.options.length==1) break;
list.size+=(list.size<list.options.length)?1:0;
cmi.listsize=list.size;
break;
case 'importListMaximize': // toggle listbox size between current and maximum
if (list.options.length==1) break;
list.size=(list.size==list.options.length)?cmi.listsize:list.options.length;
break;
}
}
//}}}
//{{{
config.macros.importTiddlers.showPanel=function(place,show,skipAnim) {
if (typeof place=='string') var place=document.getElementById(place);
if (!place||!place.style) return;
if(!skipAnim && anim && config.options.chkAnimate) anim.startAnimating(new Slider(place,show,false,'none'));
else place.style.display=show?'block':'none';
}
//}}}
//{{{
function refreshImportList(selectedIndex) {
var cmi=config.macros.importTiddlers; // abbrev
var list=cmi.$('importList'); if (!list) return;
// if nothing to show, reset list content and size
if (!cmi.inbound) {
while (list.length > 0) { list.options[0] = null; }
list.options[0]=new Option(cmi.loadText,'',false,false);
list.size=cmi.listsize;
cmi.$('importLoad').disabled=false;
cmi.$('importLoad').style.display='inline';
cmi.$('importStart').disabled=true;
cmi.$('importOptions').disabled=true;
cmi.$('importOptions').style.display='none';
cmi.$('fileImportSource').disabled=false;
cmi.$('importFromFile').disabled=false;
cmi.$('importFromWeb').disabled=false;
cmi.$('importStart').value=cmi.startText;
cmi.$('importClose').value=cmi.doneText;
cmi.$('importSelectPanel').style.display='none';
cmi.$('importOptionsPanel').style.display='none';
return;
}
// there are inbound tiddlers loaded...
cmi.$('importLoad').disabled=true;
cmi.$('importLoad').style.display='none';
cmi.$('importOptions').style.display='inline';
cmi.$('importOptions').disabled=false;
cmi.$('fileImportSource').disabled=true;
cmi.$('importFromFile').disabled=true;
cmi.$('importFromWeb').disabled=true;
cmi.$('importClose').value=cmi.closeText;
if (cmi.$('importSelectPanel').style.display=='none')
cmi.showPanel('importSelectPanel',true);
// get the sort order
if (!selectedIndex) selectedIndex=0;
if (selectedIndex==0) cmi.sort='title'; // heading
if (selectedIndex==1) cmi.sort='title';
if (selectedIndex==2) cmi.sort='modified';
if (selectedIndex==3) cmi.sort='tags';
if (selectedIndex>3) {
// display selected tiddler count
for (var t=0,count=0; t < list.options.length; t++) {
if (!list.options[t].selected) continue;
if (list.options[t].value!='')
count+=1;
else { // if heading is selected, deselect it, and then select and count all in section
list.options[t].selected=false;
for ( t++; t<list.options.length && list.options[t].value!=''; t++) {
list.options[t].selected=true;
count++;
}
}
}
clearMessage(); displayMessage(cmi.countMsg.format([count]));
}
cmi.$('importStart').disabled=!count;
if (selectedIndex>3) return; // no refresh needed
// get the alphasorted list of tiddlers
var tiddlers=cmi.inbound;
tiddlers.sort(function (a,b) {if(a['title'] == b['title']) return(0); else return (a['title'] < b['title']) ? -1 : +1; });
// clear current list contents
while (list.length > 0) { list.options[0] = null; }
// add heading and control items to list
var i=0;
var indent=String.fromCharCode(160)+String.fromCharCode(160);
if (cmi.all.length==tiddlers.length)
var summary=cmi.summaryMsg.format([tiddlers.length,(tiddlers.length!=1)?cmi.plural:cmi.single]);
else
var summary=cmi.summaryFilteredMsg.format([tiddlers.length,cmi.all.length,(cmi.all.length!=1)?cmi.plural:cmi.single]);
list.options[i++]=new Option(summary,'',false,false);
list.options[i++]=new Option(((cmi.sort=='title' )?'>':indent)+' [by title]','',false,false);
list.options[i++]=new Option(((cmi.sort=='modified')?'>':indent)+' [by date]','',false,false);
list.options[i++]=new Option(((cmi.sort=='tags')?'>':indent)+' [by tags]','',false,false);
// output the tiddler list
switch(cmi.sort) {
case 'title':
for(var t = 0; t < tiddlers.length; t++)
list.options[i++] = new Option(tiddlers[t].title,tiddlers[t].title,false,false);
break;
case 'modified':
// sort descending for newest date first
tiddlers.sort(function (a,b) {if(a['modified'] == b['modified']) return(0); else return (a['modified'] > b['modified']) ? -1 : +1; });
var lastSection = '';
for(var t = 0; t < tiddlers.length; t++) {
var tiddler = tiddlers[t];
var theSection = tiddler.modified.toLocaleDateString();
if (theSection != lastSection) {
list.options[i++] = new Option(theSection,'',false,false);
lastSection = theSection;
}
list.options[i++] = new Option(indent+indent+tiddler.title,tiddler.title,false,false);
}
break;
case 'tags':
var theTitles = {}; // all tiddler titles, hash indexed by tag value
var theTags = new Array();
for(var t=0; t<tiddlers.length; t++) {
var title=tiddlers[t].title;
var tags=tiddlers[t].tags;
if (!tags || !tags.length) {
if (theTitles['untagged']==undefined) { theTags.push('untagged'); theTitles['untagged']=new Array(); }
theTitles['untagged'].push(title);
}
else for(var s=0; s<tags.length; s++) {
if (theTitles[tags[s]]==undefined) { theTags.push(tags[s]); theTitles[tags[s]]=new Array(); }
theTitles[tags[s]].push(title);
}
}
theTags.sort();
for(var tagindex=0; tagindex<theTags.length; tagindex++) {
var theTag=theTags[tagindex];
list.options[i++]=new Option(theTag,'',false,false);
for(var t=0; t<theTitles[theTag].length; t++)
list.options[i++]=new Option(indent+indent+theTitles[theTag][t],theTitles[theTag][t],false,false);
}
break;
}
list.selectedIndex=selectedIndex; // select current control item
if (list.size<cmi.listsize) list.size=cmi.listsize;
if (list.size>list.options.length) list.size=list.options.length;
}
//}}}
//{{{
// re-entrant processing for handling import with interactive collision prompting
function importTiddlers(startIndex) {
var cmi=config.macros.importTiddlers; // abbrev
if (!cmi.inbound) return -1;
var list=cmi.$('importList'); if (!list) return;
var t;
// if starting new import, reset import status flags
if (startIndex==0)
for (var t=0;t<cmi.inbound.length;t++)
cmi.inbound[t].status='';
for (var i=startIndex; i<list.options.length; i++) {
// if list item is not selected or is a heading (i.e., has no value), skip it
if ((!list.options[i].selected) || ((t=list.options[i].value)==''))
continue;
for (var j=0;j<cmi.inbound.length;j++)
if (cmi.inbound[j].title==t) break;
var inbound = cmi.inbound[j];
var theExisting = store.getTiddler(inbound.title);
// avoid redundant import for tiddlers that are listed multiple times (when 'by tags')
if (inbound.status=='added')
continue;
// don't import the 'ImportedTiddlers' history from the other document...
if (inbound.title=='ImportedTiddlers')
continue;
// if tiddler exists and import not marked for replace or merge, stop importing
if (theExisting && (inbound.status.substr(0,7)!='replace') && (inbound.status.substr(0,5)!='merge'))
return i;
// assemble tags (remote + existing + added)
var newTags = '';
if (cmi.importTags)
newTags+=inbound.getTags() // import remote tags
if (cmi.keepTags && theExisting)
newTags+=' '+theExisting.getTags(); // keep existing tags
if (cmi.addTags && cmi.newTags.trim().length)
newTags+=' '+cmi.newTags; // add new tags
inbound.set(null,null,null,null,newTags.trim());
// set the status to 'added' (if not already set by the 'ask the user' UI)
inbound.status=(inbound.status=='')?'added':inbound.status;
// set sync fields
if (cmi.sync) {
if (!inbound.fields) inbound.fields={}; // for TW2.1.x backward-compatibility
inbound.fields['server.page.revision']=inbound.modified.convertToYYYYMMDDHHMM();
inbound.fields['server.type']='file';
inbound.fields['server.host']=(cmi.local?'file://':'')+cmi.src;
}
// do the import!
store.suspendNotifications();
store.saveTiddler(inbound.title, inbound.title, inbound.text, inbound.modifier, inbound.modified, inbound.tags, inbound.fields, true, inbound.created);
store.fetchTiddler(inbound.title).created = inbound.created; // force creation date to imported value (needed for TW2.1.x and earlier)
store.resumeNotifications();
}
return(-1); // signals that we really finished the entire list
}
function importStopped() {
var cmi=config.macros.importTiddlers; // abbrev
var list=cmi.$('importList'); if (!list) return;
var theNewTitle=cmi.$('importNewTitle');
if (cmi.index==-1){
cmi.$('importStart').value=cmi.startText;
importReport(); // import finished... generate the report
} else {
// import collision...
// show the collision panel and set the title edit field
cmi.$('importStart').value=cmi.stopText;
cmi.showPanel('importCollisionPanel',true);
theNewTitle.value=list.options[cmi.index].value;
if (cmi.$('importApplyToAll').checked && cmi.lastAction && cmi.lastAction.id!='importRename')
onClickImportButton(cmi.lastAction);
}
}
//}}}
//{{{
function importReport() {
var cmi=config.macros.importTiddlers; // abbrev
if (!cmi.inbound) return;
// if import was not completed, the collision panel will still be open... close it now.
var panel=cmi.$('importCollisionPanel'); if (panel) panel.style.display='none';
// get the alphasorted list of tiddlers
var tiddlers = cmi.inbound;
// gather the statistics
var count=0; var total=0;
for (var t=0; t<tiddlers.length; t++) {
if (!tiddlers[t].status || !tiddlers[t].status.trim().length) continue;
if (tiddlers[t].status.substr(0,7)!='skipped') count++;
total++;
}
// generate a report
if (total) displayMessage(cmi.processedMsg.format([total]));
if (count && config.options.chkImportReport) {
// get/create the report tiddler
var theReport = store.getTiddler('ImportedTiddlers');
if (!theReport) { theReport=new Tiddler(); theReport.title='ImportedTiddlers'; theReport.text=''; }
// format the report content
var now = new Date();
var newText = 'On '+now.toLocaleString()+', '+config.options.txtUserName
newText +=' imported '+count+' tiddler'+(count==1?'':'s')+' from\n[['+cmi.src+'|'+cmi.src+']]:\n';
if (cmi.addTags && cmi.newTags.trim().length)
newText += 'imported tiddlers were tagged with: "'+cmi.newTags+'"\n';
newText += '<<<\n';
for (var t=0; t<tiddlers.length; t++) if (tiddlers[t].status)
newText += '#[['+tiddlers[t].title+']] - '+tiddlers[t].status+'\n';
newText += '<<<\n';
// update the ImportedTiddlers content and show the tiddler
theReport.text = newText+((theReport.text!='')?'\n----\n':'')+theReport.text;
theReport.modifier = config.options.txtUserName;
theReport.modified = new Date();
store.saveTiddler(theReport.title, theReport.title, theReport.text, theReport.modifier, theReport.modified, theReport.tags, theReport.fields);
story.displayTiddler(null,theReport.title,1,null,null,false);
story.refreshTiddler(theReport.title,1,true);
}
// reset status flags
for (var t=0; t<cmi.inbound.length; t++) cmi.inbound[t].status='';
// mark document as dirty and let display update as needed
if (count) { store.setDirty(true); store.notifyAll(); }
// always show final message when tiddlers were actually loaded
if (count) displayMessage(cmi.importedMsg.format([count,tiddlers.length,cmi.src.replace(/%20/g,' ')]));
}
//}}}
//{{{
// // File and XMLHttpRequest I/O
config.macros.importTiddlers.askForFilename=function(here) {
var msg=here.title; // use tooltip as dialog box message
var path=getLocalPath(document.location.href);
var slashpos=path.lastIndexOf('/'); if (slashpos==-1) slashpos=path.lastIndexOf('\\');
if (slashpos!=-1) path = path.substr(0,slashpos+1); // remove filename from path, leave the trailing slash
var file='';
var result='';
if(window.Components) { // moz
try {
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
var nsIFilePicker = window.Components.interfaces.nsIFilePicker;
var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
picker.init(window, msg, nsIFilePicker.modeOpen);
var thispath = Components.classes['@mozilla.org/file/local;1'].createInstance(Components.interfaces.nsILocalFile);
thispath.initWithPath(path);
picker.displayDirectory=thispath;
picker.defaultExtension='html';
picker.defaultString=file;
picker.appendFilters(nsIFilePicker.filterAll|nsIFilePicker.filterText|nsIFilePicker.filterHTML);
if (picker.show()!=nsIFilePicker.returnCancel) var result=picker.file.persistentDescriptor;
}
catch(e) { alert('error during local file access: '+e.toString()) }
}
else { // IE
try { // XPSP2 IE only
var s = new ActiveXObject('UserAccounts.CommonDialog');
s.Filter='All files|*.*|Text files|*.txt|HTML files|*.htm;*.html|';
s.FilterIndex=3; // default to HTML files;
s.InitialDir=path;
s.FileName=file;
if (s.showOpen()) var result=s.FileName;
}
catch(e) { // fallback
var result=prompt(msg,path+file);
}
}
return result;
}
config.macros.importTiddlers.loadRemoteFile = function(src,callback) {
if (src==undefined || !src.length) return null; // filename is required
var original=src; // URL as specified
var hashpos=src.indexOf('#'); if (hashpos!=-1) src=src.substr(0,hashpos); // URL with #... suffix removed (needed for IE)
clearMessage();
displayMessage(this.openMsg.format([src.replace(/%20/g,' ')]));
if (src.substr(0,5)!='http:' && src.substr(0,5)!='file:') { // if not a URL, read from local filesystem
var txt=loadFile(src);
if (!txt) { // file didn't load, might be relative path.. try fixup
var pathPrefix=document.location.href; // get current document path and trim off filename
var slashpos=pathPrefix.lastIndexOf('/'); if (slashpos==-1) slashpos=pathPrefix.lastIndexOf('\\');
if (slashpos!=-1 && slashpos!=pathPrefix.length-1) pathPrefix=pathPrefix.substr(0,slashpos+1);
src=pathPrefix+src;
if (pathPrefix.substr(0,5)!='http:') src=getLocalPath(src);
var txt=loadFile(src);
}
if (!txt) { // file still didn't load, report error
displayMessage(config.macros.importTiddlers.openErrMsg.format([src.replace(/%20/g,' '),'(filesystem error)']));
} else {
displayMessage(config.macros.importTiddlers.readMsg.format([txt.length,src.replace(/%20/g,' ')]));
if (version.major+version.minor*.1+version.revision*.01<2.52) txt=convertUTF8ToUnicode(txt);
if (callback) callback(true,original,txt,src,null);
}
} else {
doHttp('GET',src,null,null,config.options.txtRemoteUsername,config.options.txtRemotePassword,callback,original,null);
}
}
config.macros.importTiddlers.readTiddlersFromHTML=function(html)
{
var remoteStore=new TiddlyWiki();
remoteStore.importTiddlyWiki(html);
return remoteStore.getTiddlers('title');
}
config.macros.importTiddlers.readTiddlersFromCSV=function(CSV) {
var remoteStore=new TiddlyWiki();
var lines=CSV.split('\n'); var names=lines[0].split(','); CSV=lines.join('\n')
// ENCODE commas and newlines within quoted values
var comma='!~comma~!'; var commaRE=new RegExp(comma,'g');
var newline='!~newline~!'; var newlineRE=new RegExp(newline,'g');
CSV=CSV.replace(/\x22((?:[^\x22]|\x22\x22)*?)\x22/g,
function(x){ return x.substr(1,x.length-2).replace(/\,/g,comma).replace(/\n/g,newline); });
// PARSE lines
var lines=CSV.split('\n');
for (var i=1; i<lines.length; i++) { if (!lines[i].length) continue;
var values=lines[i].split(',');
// DECODE commas, newlines and doubled-quotes within quoted values
for (var v=0; v<values.length; v++)
values[v]=values[v].replace(commaRE,',').replace(newlineRE,'\n').replace(/\x22\x22/g,'\x22');
// EXTRACT tiddler values
var title=''; var text=''; var tags=[]; var fields={};
var created=null; var when=new Date(); var who=config.options.txtUserName;
for (var v=0; v<values.length; v++) { var val=values[v];
if (names[v]) switch(names[v].toLowerCase()) {
case 'title': title=val.replace(/\[\]\|/g,'_'); break;
case 'created': created=new Date(val); break;
case 'modified':when=new Date(val); break;
case 'modifier':who=val; break;
case 'text': text=val; break;
case 'tags': tags=val.readBracketedList(); break;
default: fields[names[v].toLowerCase()]=val; break;
}
}
// CREATE tiddler in temporary store
if (title.length) remoteStore.saveTiddler(title,title,text,who,when,tags,fields,true,created||when);
}
return remoteStore.getTiddlers('title');
}
config.macros.importTiddlers.filterTiddlerList=function(success,params,txt,src,xhr) {
var cmi=config.macros.importTiddlers; // abbreviation
var src=src.replace(/%20/g,' ');
if (!success) { displayMessage(cmi.openErrMsg.format([src,xhr.status])); return; }
cmi.all=cmi.readTiddlersFromHTML(txt);
if (!cmi.all||!cmi.all.length) cmi.all=cmi.readTiddlersFromCSV(txt)
var count=cmi.all?cmi.all.length:0;
var querypos=src.lastIndexOf('?'); if (querypos!=-1) src=src.substr(0,querypos);
displayMessage(cmi.foundMsg.format([count,src]));
cmi.inbound=cmi.filterByHash(params,cmi.all); // use full URL including hash (if any)
cmi.$('importLastFilter').value=cmi.lastFilter;
window.refreshImportList(0);
}
config.macros.importTiddlers.filterByHash=function(src,tiddlers)
{
var hashpos=src.lastIndexOf('#'); if (hashpos==-1) return tiddlers;
var hash=src.substr(hashpos+1); if (!hash.length) return tiddlers;
var tids=[];
var params=hash.parseParams('anon',null,true,false,false);
for (var p=1; p<params.length; p++) {
switch (params[p].name) {
case 'anon':
case 'open':
tids.pushUnique(params[p].value);
break;
case 'tag':
if (store.getMatchingTiddlers) { // for boolean expressions - see MatchTagsPlugin
var r=store.getMatchingTiddlers(params[p].value,null,tiddlers);
for (var t=0; t<r.length; t++) tids.pushUnique(r[t].title);
} else for (var t=0; t<tiddlers.length; t++)
if (tiddlers[t].isTagged(params[p].value))
tids.pushUnique(tiddlers[t].title);
break;
case 'story':
for (var t=0; t<tiddlers.length; t++)
if (tiddlers[t].title==params[p].value) {
tiddlers[t].changed();
for (var s=0; s<tiddlers[t].links.length; s++)
tids.pushUnique(tiddlers[t].links[s]);
break;
}
break;
case 'search':
for (var t=0; t<tiddlers.length; t++)
if (tiddlers[t].text.indexOf(params[p].value)!=-1)
tids.pushUnique(tiddlers[t].title);
break;
}
}
var matches=[];
for (var t=0; t<tiddlers.length; t++)
if (tids.contains(tiddlers[t].title))
matches.push(tiddlers[t]);
displayMessage(config.macros.importTiddlers.filterMsg.format([matches.length,hash]));
config.macros.importTiddlers.lastFilter=hash;
return matches;
}
//}}}
On Fri Jul 24 19:55:05 2009, sww imported 1 tiddler from
[[http://mptwcadfael.tiddlyspot.com|http://mptwcadfael.tiddlyspot.com]]:
<<<
#[[UploadPlugin]] - replaces UploadPlugin - 7/21/2009 14:24:00 by YourName
<<<
----
On Fri Jul 24 19:54:25 2009, sww imported 1 tiddler from
[[http://tiddlysquat.tiddlyspot.com/|http://tiddlysquat.tiddlyspot.com/]]:
<<<
#[[TspotSetupPlugin]] - replaces TspotSetupPlugin - 8/8/2008 06:41:00 by YourName
<<<
----
On Fri Jul 24 19:15:32 2009, sww imported 84 tiddlers from
[[http://mptwcadfael.tiddlyspot.com/|http://mptwcadfael.tiddlyspot.com/]]:
<<<
#[[2 July 2009]] - added
#[[31 July 2009]] - added
#[[Bert]] - added
#[[Budget]] - added
#[[CalendarPlugin]] - added
#[[CleanupContentPlugin]] - added
#[[CloseOnCancelPlugin]] - replaces CloseOnCancelPlugin - 6/3/2009 08:03:00 by MPTW
#[[ContentsSlider]] - added
#[[DatePlugin]] - added
#[[DefaultTiddlers]] - added
#[[ExtendTagButtonPlugin]] - replaces ExtendTagButtonPlugin - 6/3/2009 08:03:00 by MPTW
#[[HelloThere]] - added
#[[HideWhenPlugin]] - replaces HideWhenPlugin - 6/3/2009 08:03:00 by MPTW
#[[ImageFunctionsTest]] - added
#[[ImagePopupPlugin]] - added
#[[ImagePopupTestImage]] - added
#[[ImageSizePlugin]] - added
#[[ImportTiddlersPlugin]] - replaces ImportTiddlersPlugin - 7/24/2009 19:04:00 by YourName
#[[InlineJavascriptPlugin]] - added
#[[InstantTimestampPlugin]] - replaces InstantTimestampPlugin - 6/3/2009 08:03:00 by MPTW
#[[Leo]] - added
#[[LessBackupsPlugin]] - replaces LessBackupsPlugin - 6/3/2009 08:03:00 by MPTW
#[[LoadRemoteFileThroughProxy]] - replaces LoadRemoteFileThroughProxy - 7/24/2009 18:39:00 by YourName
#[[MPTW]] - replaces MPTW - 6/3/2009 08:03:00 by MPTW
#[[MainMenu]] - added
#[[Meeting with Leo - 12 Oct]] - added
#[[Meetings]] - added
#[[MemorizablePlugin]] - added
#[[MptwBlack]] - replaces MptwBlack - 6/3/2009 08:03:00 by MPTW
#[[MptwBlue]] - replaces MptwBlue - 6/3/2009 08:03:00 by MPTW
#[[MptwConfigPlugin]] - replaces MptwConfigPlugin - 6/3/2009 08:03:00 by MPTW
#[[MptwGreen]] - replaces MptwGreen - 6/3/2009 08:03:00 by MPTW
#[[MptwRed]] - replaces MptwRed - 6/3/2009 08:03:00 by MPTW
#[[MptwRoundTheme]] - replaces MptwRoundTheme - 6/3/2009 08:03:00 by MPTW
#[[MptwSmoke]] - replaces MptwSmoke - 6/3/2009 08:03:00 by MPTW
#[[MptwStandardTheme]] - replaces MptwStandardTheme - 6/3/2009 08:03:00 by MPTW
#[[MptwTeal]] - replaces MptwTeal - 6/3/2009 08:03:00 by MPTW
#[[MptwTheme]] - replaces MptwTheme - 6/3/2009 08:03:00 by MPTW
#[[MptwTrimTheme]] - replaces MptwTrimTheme - 6/3/2009 08:03:00 by MPTW
#[[MptwUpgradeURL]] - replaces MptwUpgradeURL - 6/3/2009 08:03:00 by MPTW
#[[MptwUserConfigPlugin]] - replaces MptwUserConfigPlugin - 6/3/2009 08:03:00 by MPTW
#[[MyStuff]] - added
#[[NestedSlidersPlugin]] - added
#[[NewHerePlugin]] - replaces NewHerePlugin - 6/3/2009 08:03:00 by MPTW
#[[NewMeansNewPlugin]] - replaces NewMeansNewPlugin - 6/3/2009 08:03:00 by MPTW
#[[PageTemplate]] - added
#[[PasswordOptionsPlugin]] - replaces PasswordOptionsPlugin - 7/24/2009 18:39:00 by YourName
#[[People]] - added
#[[PostsLog]] - added
#[[PrettyDatesPlugin]] - replaces PrettyDatesPlugin - 6/3/2009 08:03:00 by MPTW
#[[QuickOpenTagPlugin]] - replaces QuickOpenTagPlugin - 6/3/2009 08:03:00 by MPTW
#[[Quotations]] - added
#[[QuoteOfTheDayPlugin]] - added
#[[ReminderMacros]] - added
#[[RenameTagsPlugin]] - replaces RenameTagsPlugin - 6/3/2009 08:03:00 by MPTW
#[[Sam]] - added
#[[SaveCloseTiddlerPlugin]] - replaces SaveCloseTiddlerPlugin - 6/3/2009 08:03:00 by MPTW
#[[SelectThemePlugin]] - replaces SelectThemePlugin - 6/3/2009 08:03:00 by MPTW
#[[ShowPopup]] - added
#[[ShowPopupTest]] - added
#[[SimpleSearchPlugin]] - added
#[[SiteSubtitle]] - added
#[[SiteTitle]] - added
#[[StyleSheet]] - added
#[[SwwTags]] - added
#[[SwwTweaks]] - added
#[[SystemInfoPlugin]] - added
#[[TabAllTags]] - replaces TabAllTags - 6/3/2009 08:03:00 by MPTW
#[[TabMore]] - replaces TabMore - 6/3/2009 08:03:00 by MPTW
#[[TabTags]] - replaces TabTags - 6/3/2009 08:03:00 by MPTW
#[[TagglyTaggingPlugin]] - replaces TagglyTaggingPlugin - 6/3/2009 08:03:00 by MPTW
#[[TiddlerTweakerPlugin]] - added
#[[ToggleRightSidebar]] - added
#[[ToggleTagPlugin]] - replaces ToggleTagPlugin - 6/3/2009 08:03:00 by MPTW
#[[TspotSetupPlugin]] - replaces TspotSetupPlugin - 8/8/2008 06:41:00 by YourName
#[[UploadLog]] - replaces UploadLog - 7/24/2009 19:13:00 by YourName
#[[UploadPlugin]] - replaces UploadPlugin - 7/24/2009 18:39:00 by YourName
#[[contentHeader]] - added
#[[done]] - added
#[[log]] - added
#[[ref]] - added
#[[sww]] - added
#[[systemConfig]] - replaces systemConfig - 6/3/2009 08:03:00 by MPTW
#[[todo]] - added
<<<
/***
|Name|InlineJavascriptPlugin|
|Source|http://www.TiddlyTools.com/#InlineJavascriptPlugin|
|Documentation|http://www.TiddlyTools.com/#InlineJavascriptPluginInfo|
|Version|1.9.4|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Insert Javascript executable code directly into your tiddler content.|
''Call directly into TW core utility routines, define new functions, calculate values, add dynamically-generated TiddlyWiki-formatted output'' into tiddler content, or perform any other programmatic actions each time the tiddler is rendered.
!!!!!Documentation
>see [[InlineJavascriptPluginInfo]]
!!!!!Revisions
<<<
2009.02.26 [1.9.4] in $(), handle leading '#' on ID for compatibility with JQuery syntax
|please see [[InlineJavascriptPluginInfo]] for additional revision details|
2005.11.08 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.InlineJavascriptPlugin= {major: 1, minor: 9, revision: 3, date: new Date(2008,6,11)};
config.formatters.push( {
name: "inlineJavascript",
match: "\\<script",
lookahead: "\\<script(?: src=\\\"((?:.|\\n)*?)\\\")?(?: label=\\\"((?:.|\\n)*?)\\\")?(?: title=\\\"((?:.|\\n)*?)\\\")?(?: key=\\\"((?:.|\\n)*?)\\\")?( show)?\\>((?:.|\\n)*?)\\</script\\>",
handler: function(w) {
var lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart) {
var src=lookaheadMatch[1];
var label=lookaheadMatch[2];
var tip=lookaheadMatch[3];
var key=lookaheadMatch[4];
var show=lookaheadMatch[5];
var code=lookaheadMatch[6];
if (src) { // load a script library
// make script tag, set src, add to body to execute, then remove for cleanup
var script = document.createElement("script"); script.src = src;
document.body.appendChild(script); document.body.removeChild(script);
}
if (code) { // there is script code
if (show) // show inline script code in tiddler output
wikify("{{{\n"+lookaheadMatch[0]+"\n}}}\n",w.output);
if (label) { // create a link to an 'onclick' script
// add a link, define click handler, save code in link (pass 'place'), set link attributes
var link=createTiddlyElement(w.output,"a",null,"tiddlyLinkExisting",wikifyPlainText(label));
var fixup=code.replace(/document.write\s*\(/gi,'place.bufferedHTML+=(');
link.code="function _out(place){"+fixup+"\n};_out(this);"
link.tiddler=w.tiddler;
link.onclick=function(){
this.bufferedHTML="";
try{ var r=eval(this.code);
if(this.bufferedHTML.length || (typeof(r)==="string")&&r.length)
var s=this.parentNode.insertBefore(document.createElement("span"),this.nextSibling);
if(this.bufferedHTML.length)
s.innerHTML=this.bufferedHTML;
if((typeof(r)==="string")&&r.length) {
wikify(r,s,null,this.tiddler);
return false;
} else return r!==undefined?r:false;
} catch(e){alert(e.description||e.toString());return false;}
};
link.setAttribute("title",tip||"");
var URIcode='javascript:void(eval(decodeURIComponent(%22(function(){try{';
URIcode+=encodeURIComponent(encodeURIComponent(code.replace(/\n/g,' ')));
URIcode+='}catch(e){alert(e.description||e.toString())}})()%22)))';
link.setAttribute("href",URIcode);
link.style.cursor="pointer";
if (key) link.accessKey=key.substr(0,1); // single character only
}
else { // run inline script code
var fixup=code.replace(/document.write\s*\(/gi,'place.innerHTML+=(');
var c="function _out(place){"+fixup+"\n};_out(w.output);";
try { var out=eval(c); }
catch(e) { out=e.description?e.description:e.toString(); }
if (out && out.length) wikify(out,w.output,w.highlightRegExp,w.tiddler);
}
}
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
}
} )
//}}}
// // Backward-compatibility for TW2.1.x and earlier
//{{{
if (typeof(wikifyPlainText)=="undefined") window.wikifyPlainText=function(text,limit,tiddler) {
if(limit > 0) text = text.substr(0,limit);
var wikifier = new Wikifier(text,formatter,null,tiddler);
return wikifier.wikifyPlain();
}
//}}}
// // GLOBAL FUNCTION: $(...) -- 'shorthand' convenience syntax for document.getElementById()
//{{{
if (typeof($)=='undefined') { function $(id) { return document.getElementById(id.replace(/^#/,'')); } }
//}}}
/***
|Name:|InstantTimestampPlugin|
|Description:|A handy way to insert timestamps in your tiddler content|
|Version:|1.0.10 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#InstantTimestampPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
If you enter {ts} in your tiddler content (without the spaces) it will be replaced with a timestamp when you save the tiddler. Full list of formats:
* {ts} or {t} -> timestamp
* {ds} or {d} -> datestamp
* !ts or !t at start of line -> !!timestamp
* !ds or !d at start of line -> !!datestamp
(I added the extra ! since that's how I like it. Remove it from translations below if required)
!!Notes
* Change the timeFormat and dateFormat below to suit your preference.
* See also http://mptw2.tiddlyspot.com/#AutoCorrectPlugin
* You could invent other translations and add them to the translations array below.
***/
//{{{
config.InstantTimestamp = {
// adjust to suit
timeFormat: 'DD/0MM/YY 0hh:0mm',
dateFormat: 'DD/0MM/YY',
translations: [
[/^!ts?$/img, "'!!{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
[/^!ds?$/img, "'!!{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"],
// thanks Adapted Cat
[/\{ts?\}(?!\}\})/ig,"'{{ts{'+now.formatString(config.InstantTimestamp.timeFormat)+'}}}'"],
[/\{ds?\}(?!\}\})/ig,"'{{ds{'+now.formatString(config.InstantTimestamp.dateFormat)+'}}}'"]
],
excludeTags: [
"noAutoCorrect",
"noTimestamp",
"html",
"CSS",
"css",
"systemConfig",
"systemConfigDisabled",
"zsystemConfig",
"Plugins",
"Plugin",
"plugins",
"plugin",
"javascript",
"code",
"systemTheme",
"systemPalette"
],
excludeTiddlers: [
"StyleSheet",
"StyleSheetLayout",
"StyleSheetColors",
"StyleSheetPrint"
// more?
]
};
TiddlyWiki.prototype.saveTiddler_mptw_instanttimestamp = TiddlyWiki.prototype.saveTiddler;
TiddlyWiki.prototype.saveTiddler = function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created) {
tags = tags ? tags : []; // just in case tags is null
tags = (typeof(tags) == "string") ? tags.readBracketedList() : tags;
var conf = config.InstantTimestamp;
if ( !tags.containsAny(conf.excludeTags) && !conf.excludeTiddlers.contains(newTitle) ) {
var now = new Date();
var trans = conf.translations;
for (var i=0;i<trans.length;i++) {
newBody = newBody.replace(trans[i][0], eval(trans[i][1]));
}
}
// TODO: use apply() instead of naming all args?
return this.saveTiddler_mptw_instanttimestamp(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created);
}
// you can override these in StyleSheet
setStylesheet(".ts,.ds { font-style:italic; }","instantTimestampStyles");
//}}}
/***
|Name:|LessBackupsPlugin|
|Description:|Intelligently limit the number of backup files you create|
|Version:|3.0.1 ($Rev: 2320 $)|
|Date:|$Date: 2007-06-18 22:37:46 +1000 (Mon, 18 Jun 2007) $|
|Source:|http://mptw.tiddlyspot.com/#LessBackupsPlugin|
|Author:|Simon Baird|
|Email:|simon.baird@gmail.com|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Description
You end up with just backup one per year, per month, per weekday, per hour, minute, and second. So total number won't exceed about 200 or so. Can be reduced by commenting out the seconds/minutes/hours line from modes array
!!Notes
Works in IE and Firefox only. Algorithm by Daniel Baird. IE specific code by by Saq Imtiaz.
***/
//{{{
var MINS = 60 * 1000;
var HOURS = 60 * MINS;
var DAYS = 24 * HOURS;
if (!config.lessBackups) {
config.lessBackups = {
// comment out the ones you don't want or set config.lessBackups.modes in your 'tweaks' plugin
modes: [
["YYYY", 365*DAYS], // one per year for ever
["MMM", 31*DAYS], // one per month
["ddd", 7*DAYS], // one per weekday
//["d0DD", 1*DAYS], // one per day of month
["h0hh", 24*HOURS], // one per hour
["m0mm", 1*HOURS], // one per minute
["s0ss", 1*MINS], // one per second
["latest",0] // always keep last version. (leave this).
]
};
}
window.getSpecialBackupPath = function(backupPath) {
var now = new Date();
var modes = config.lessBackups.modes;
for (var i=0;i<modes.length;i++) {
// the filename we will try
var specialBackupPath = backupPath.replace(/(\.)([0-9]+\.[0-9]+)(\.html)$/,
'$1'+now.formatString(modes[i][0]).toLowerCase()+'$3')
// open the file
try {
if (config.browser.isIE) {
var fsobject = new ActiveXObject("Scripting.FileSystemObject")
var fileExists = fsobject.FileExists(specialBackupPath);
if (fileExists) {
var fileObject = fsobject.GetFile(specialBackupPath);
var modDate = new Date(fileObject.DateLastModified).valueOf();
}
}
else {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(specialBackupPath);
var fileExists = file.exists();
if (fileExists) {
var modDate = file.lastModifiedTime;
}
}
}
catch(e) {
// give up
return backupPath;
}
// expiry is used to tell if it's an 'old' one. Eg, if the month is June and there is a
// June file on disk that's more than an month old then it must be stale so overwrite
// note that "latest" should be always written because the expiration period is zero (see above)
var expiry = new Date(modDate + modes[i][1]);
if (!fileExists || now > expiry)
return specialBackupPath;
}
}
// hijack the core function
window.getBackupPath_mptw_orig = window.getBackupPath;
window.getBackupPath = function(localPath) {
return getSpecialBackupPath(getBackupPath_mptw_orig(localPath));
}
//}}}
/***
|''Name:''|LoadRemoteFileThroughProxy (previous LoadRemoteFileHijack)|
|''Description:''|When the TiddlyWiki file is located on the web (view over http) the content of [[SiteProxy]] tiddler is added in front of the file url. If [[SiteProxy]] does not exist "/proxy/" is added. |
|''Version:''|1.1.0|
|''Date:''|mar 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#LoadRemoteFileHijack|
|''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|
***/
//{{{
version.extensions.LoadRemoteFileThroughProxy = {
major: 1, minor: 1, revision: 0,
date: new Date("mar 17, 2007"),
source: "http://tiddlywiki.bidix.info/#LoadRemoteFileThroughProxy"};
if (!window.bidix) window.bidix = {}; // bidix namespace
if (!bidix.core) bidix.core = {};
bidix.core.loadRemoteFile = loadRemoteFile;
loadRemoteFile = function(url,callback,params)
{
if ((document.location.toString().substr(0,4) == "http") && (url.substr(0,4) == "http")){
url = store.getTiddlerText("SiteProxy", "/proxy/") + url;
}
return bidix.core.loadRemoteFile(url,callback,params);
}
//}}}
MPTW is a distribution or edition of TiddlyWiki that includes a standard TiddlyWiki core packaged with some plugins designed to improve usability and provide a better way to organise your information. For more information see http://mptw.tiddlyspot.com/.
WelcomeToTiddlyspot
GettingStarted
SwwTweaks
<<tag Plugins|systemConfig>>
<<tag sww>>
@@padding-left:25em;<<search>>@@ @@padding-left:1em; <<tiddler ToggleRightSidebar>>@@
here are some meeting notes
/***
!!!<<gradient horiz #fc3 #fff>> MemorizablePlugin^^<<tiddler CloseThisOpen with: ThirdPartyPlugins '« back'>>|<<toolbar editTiddler>>» ^^>>
|Name|MemorizablePlugin|
|Source|URL: http://memorizable.com|
|Version|1.0.0|
|Author|Craig D. Muth Copyright (c) 2007|
|For use in TiddlyWiki see|http://tinyurl.com/34fjk6|
***/
//{{{
// License
//
// Note: This is a modified version of the X11 (aka MIT) open source
// license. It lets you use, modify, distribute and sell, etc.,
// requiring only that you leave the "Help" and "About Memorizable
// Tables" links (under "Options") in tact. If you desire to use the
// software without these links please contact the author.
//
// COPYRIGHT AND PERMISSION NOTICE for Memorizable Tables
//
// Copyright (c) 2007, Craig D. Muth, memorizable.com
// Author's Website URL: http://memorizable.com
//
// All rights reserved.
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished
// to do so, subject to the following conditions:
//
// The above copyright notice, Author's Website URL, and this
// permission notice shall be included in all copies or substantial
// portions of the Software, and any hyperlinks in the user interface
// in the Software which refer to any page on the Author's Website may
// not be removed, disabled, altered, obscured, or repositioned.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// Except as contained in this notice, the name of a copyright holder
// shall not be used in advertising or otherwise to promote the sale,
// use or other dealings in this Software without prior written
// authorization of the copyright holder.
//
Mem = new Object();
Mem.blankRowCount = 9;
Mem.mGray = "#d8d4c0";
Mem.mGreen = "#fff";
Mem.mClicked = "#b8b4a0";
Mem.myCellIndex = function(th) {
var cells = th.parentNode.cells;
var inn = 0;
for(var x=0; x<cells.length; x++) {
if(cells.item(x) == th)
inn = x;
}
return inn;
}
Mem.start = function( item ) {
var columnClicked;
item.parentNode.parentNode.parentNode.parentNode.isMem = true;
var t = this.setT( item );
columnClicked = Mem.myCellIndex(item.parentNode);
// If already in progress
if( t.s && t.s.tbodyBackup ) {
// Kill blinking processes
this.tChile('directionsDiv').cycles = 1;
Mem.restore();
}
// Create new if necessary
if( typeof( t.s ) != 'object')
t.s = new Array();
t.s.column = columnClicked;
// Create backup
var bak = t.tBodies[0].cloneNode( true );
t.s.tbodyBackup = bak;
// Init correct count
t.s.correctCount = 0;
t.s.pending = new Array();
var initialLength = t.tBodies[0].rows.length;
for(var x=1; x<initialLength; x++) {
// Build up list of indexes
t.s.pending[t.s.pending.length] = t.tBodies[0].rows[1];
// Remove from table
t.tBodies[0].removeChild( t.tBodies[0].rows[1] );
}
t.s.totalQuestions = t.s.pending.length;
var tds = t.s.pending[0].getElementsByTagName("TD");
var numberOfColumns=tds.length;
// Add blank rows to end
for(var x=1; x<t.s.pending.length; x++) {
if( x <= this.blankRowCount ) {
var tr = document.createElement("TR");
// For each column
for(var y=0; y<numberOfColumns; y++) {
var td = document.createElement("TD"); td.innerHTML = " ";
tr.appendChild( td );
}
t.tBodies[0].appendChild( tr );
}
}
// If hidden blank rows
if( t.s.pending.length > this.blankRowCount + 1 ) {
// Add ... row
var tr = document.createElement("TR");
var td = document.createElement("TD");
// td.innerHTML = ". . .";
td.innerHTML = "<div style='text-align: center; font-weight: bold; font-size: 6px; font-family: arial black; margin-top: 2px;'>. . .</div>";
var colspan = document.createAttribute("COLSPAN");
colspan.nodeValue=numberOfColumns;
td.setAttributeNode(colspan);
tr.appendChild( td );
//numberOfColumns
t.tBodies[0].appendChild( tr );
}
this.shuffle( t.s.pending ); t.s.pending.reverse(); this.shuffle( t.s.pending );
// Add buttons, etc. to end of table.
var tr = document.createElement("TR");
var statusTd = document.createElement("TD");
statusTd.id = 'statusTd';
tr.appendChild( statusTd );
var colspan = document.createAttribute("COLSPAN");
colspan.nodeValue=numberOfColumns;
statusTd.setAttributeNode(colspan);
t.tBodies[0].appendChild( tr );
// Create placeholders for buttons, etc.
statusTd.innerHTML = "\
<div id=mode style='text-align:right; height:19px; font-size:10px; color:#666;'>" + Mem.getModeDiv(0) + "</div>\
<div id=directionsDiv style='margin-bottom:4px; text-align: left; font-size:10px; font-family:verdana,arial,sans-serif; color:#666;'></div>\
<div id=buttons style='float:left; height:21px;'></div>\
<div id=options style='padding: 5px 0px 0px 8px; width:55px; margin-top:0px; float:right;'><a href='#' onclick='return Mem.showOptions(this);' id=optionsLink>Options</a></div>\
<div id=progress style='margin-top:6px; float:right; font-size:8px; font-family:impact; color:#aaa; text-align:right; vertical-align:middle; '></div>\
" + this.getOptions();
// Enable options if enabled before
if( t.s.optionsOn )
this.showOptions( statusTd );
this.presentQuestion();
this.glow(100);
t.s.mode = "flashcard";
return false;
}
Mem.addEvent = function( obj, type, fn ) {
if ( obj.attachEvent ) {
obj['e'+type+fn] = fn;
obj[type+fn] = function() {obj['e'+type+fn]( window.event );}
obj.attachEvent( 'on'+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, false );
}
Mem.getQuestionCell = function() {
return Mem.t.s.pending[0].cells[ Mem.t.s.column ];
}
Mem.createProgressBar = function() {
var progress = "";
var progressDups = "";
var foundAlready = new Array();
for(var x=0; x<Mem.t.s.pending.length ;x++) {
// If found already
if( foundAlready[ Mem.t.s.pending[x].innerHTML ] )
progressDups += "|";
else
progress += "|";
// Remember we found this one
foundAlready[ Mem.t.s.pending[x].innerHTML ] = true;
}
return progress + "<span style='color:#f00;'>" + progressDups + "</span>";
}
Mem.presentQuestion = function() {
this.tChile('directionsDiv').innerHTML =
"<div style='text-align:center;'>Guess the answer <b style='color:#4d0'>in your head</b>.<span style='font-size:7px;'></span> Then click <b>show answer</b>, or type <b>1</b>.</div>";
this.tChile('buttons').innerHTML = "<button id=showAnswer style='margin-right:111px; width:11em; margin-bottom:1px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.showAnswer( this )' >show answer <span style='color:#aaa;text-decoration:underline;'>1</span></button>";
var iveGuessed = this.tChile('showAnswer');
Mem.addEvent( iveGuessed, 'mouseover', function(){ if(typeof( iveGuessedOnMouseOver ) =='function') iveGuessedOnMouseOver() } );
Mem.addEvent( iveGuessed, 'mouseout', function(){ if(typeof( iveGuessedOnMouseOver ) =='function') iveGuessedOnMouseOut() } );
// Add pending row
Mem.t.tBodies[0].insertBefore( Mem.t.s.pending[0], Mem.t.tBodies[0].rows[ Mem.t.s.correctCount + 1 ] );
// Insert "guess the answer", remembering old value
var questionCell = this.getQuestionCell();
Mem.t.s.questionCellOld = questionCell.innerHTML;
questionCell.innerHTML = "<span style='text-decoration:none; color:#4d0; font-weight:bold; cursor:pointer;' title=\"Guess the answer in your head. Then, click the 'show answer' button.\">what goes here?</span>";
// Help alert
Mem.addEvent( questionCell.getElementsByTagName("SPAN")[0], 'mousedown', function(){ alert('Guess the answer in your head. Then, click the \'show answer\' button at the bottom of the table.') } );
this.tChile('progress').innerHTML = this.createProgressBar();
}
Mem.showAnswer = function( button, noScroll ) {
var t = this.setT( button );
// Exit if other mode
if( t.s.mode != "flashcard" )
return;
// Exit if no answer to show
if( t.s.questionCellOld == null )
return;
var questionCell = this.getQuestionCell();
questionCell.innerHTML = t.s.questionCellOld;
t.s.questionCellOld = null;
// Default
var iWasRightText = "I was right";
// Count how many of this remaining
var timesFound = 0;
for(var x=0; x<t.s.pending.length ;x++)
if( t.s.pending[x].innerHTML == t.s.pending[0].innerHTML )
timesFound++;
// If not the last time
if( timesFound > 1 )
iWasRightText = "show later";
this.tChile('directionsDiv').innerHTML =
"<div style='text-align:center;'>Press the appropriate button based on your guess, or type <b>1</b> or <b>2</b>.</div>";
this.tChile('buttons').innerHTML = "\
<button id=iWasWrong style='width:11em; padding:0px; margin: 0px 12px 1px 0px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.answer( false, this )'>I was wrong <span style='color:#aaa;text-decoration:underline;'>1</span></button>\
<button id=iWasRight class='iWasRightButton' style='width:10em; margin-bottom:1px; font-family: verdana,arial,sans-serif; font-size:9px;' onclick='Mem.answer( true, this )' >" + iWasRightText + " <span style='color:#aaa;text-decoration:underline;'>2</span></button>\
";
this.tChile('progress').innerHTML = this.createProgressBar();
var iWasRight = this.tChile('iWasRight');
var iWasWrong = this.tChile('iWasWrong');
Mem.addEvent( iWasRight, 'mouseover', function(){ if(typeof( iWasRightOnMouseOver ) =='function') iWasRightOnMouseOver() } );
Mem.addEvent( iWasRight, 'mouseout', function(){ if(typeof( iWasRightOnMouseOut ) =='function') iWasRightOnMouseOut() } );
Mem.addEvent( iWasWrong, 'mouseover', function(){ if(typeof( iWasWrongOnMouseOver ) =='function') iWasWrongOnMouseOver() } );
Mem.addEvent( iWasWrong, 'mouseout', function(){ if(typeof( iWasWrongOnMouseOut ) =='function') iWasWrongOnMouseOut() } );
if(! noScroll)
this.scrollDownIfNecessary( this.tChile('statusTd') );
}
Mem.answer = function( correct, button, noScroll ) {
var t = this.setT( button );
// If answer not shown
if( t.s.questionCellOld != null )
return;
// If other mode
if( t.s.mode != "flashcard" )
return;
var dup = this.currentIsDuplicate();
var last = t.s.pending[0];
// Remove from front of pending
t.s.pending.splice( 0, 1 );
var allRows = t.tBodies[0].rows;
if( correct ) {
// If elsewhere in pending, remove from table
if( dup )
t.tBodies[0].removeChild( last );
// If pending is empty, they're finished
if( t.s.pending.length == 0 ) {
this.finished();
return;
}
// If not dup, increase count of correct
if( ! dup ) {
t.s.correctCount++;
// If enough rows in table, remove last one (blank or ...)
if( t.s.correctCount + this.blankRowCount >= t.s.totalQuestions - 1 )
t.tBodies[0].removeChild( allRows[allRows.length - 2] );
}
}
// If they missed it
else {
// Remove from table
t.tBodies[0].removeChild( last );
t.s.pending.push( last );
t.s.pending.splice( 2, 0, last );
}
this.presentQuestion();
if(this.tChile('directionsDiv').cycles >= 3)
this.tChile('directionsDiv').cycles = 2;
if(! noScroll)
this.scrollDownIfNecessary( this.tChile('statusTd') );
}
Mem.currentIsDuplicate = function() {
for(var x=1; x<Mem.t.s.pending.length ;x++) {
if( Mem.t.s.pending[x] == Mem.t.s.pending[0] )
return true;
}
return false;
}
Mem.message = function( s ) {
var d = document.createElement('div');
var t = document.createTextNode( s );
d.appendChild(t);
document.body.appendChild(d);
}
Mem.shuffle = function( list ) {
var holder, swaps, i, j;
for (swaps=0; swaps<(list.length*2); swaps++) {
i = Math.floor(Math.random()*list.length);
j = Math.floor(Math.random()*list.length);
holder = list[i];
list[i] = list[j];
list[j]=holder;
}
return list;
}
Mem.dump = function( o ) {
var s = "";
for(m in o)
s += m + ", ";
return s;
}
Mem.keyWasPressed = function( keyp ) {
var pressed;
if( navigator.appName == "Netscape" ) pressed = keyp.which;
if( navigator.appVersion.indexOf("MSIE") != -1 ) pressed = event.keyCode;
// In case no table in progress
try {
// Show answer
if ( ( pressed == "1".charCodeAt(0) ) || ( pressed == 97 ) ) {
// If answer not shown yet
if( Mem.t.s.questionCellOld != null )
Mem.showAnswer();
else
Mem.answer( false );
}
// TODO make sure there are no modifiers held down (because of ctrl-r)
// I was right
if ( ( pressed == "2".charCodeAt(0) ) || ( pressed == 98 ) )
Mem.answer( true );
} catch(e) {}
}
Mem.memorizeAllTables = function( item, onlyDoTheseTables ) {
// If we are a "hide" link
if( item.innerHTML == "close" ) {
item.innerHTML = item.innerHTML_old;
var removeThis = item.parentNode.getElementsByTagName("DIV")[0];
// Close and exit
item.parentNode.removeChild( removeThis );
return false;
}
// Change link to 'close'
item.innerHTML_old = item.innerHTML;
item.innerHTML = "close";
// Create table in new div
var d = document.createElement("div");
d.innerHTML = "\
<table class=\"memorizableAll\"><tr> \
<th>Left Side <a style=\"font-size: 9px;\" href=\"#\" onclick=\"return Mem.start(this)\">(memorize)</a></th> \
<th>Right Side <a style=\"font-size: 9px;\" href=\"#\" onclick=\"return Mem.start(this)\">(memorize)</a></th>\
</tr></table>";
// Get ref to it
var tb = d.getElementsByTagName("TBODY")[0];
var memTableCount = 0;
// Convert list to map
var onlyMap = [];
if( onlyDoTheseTables )
for(var x=0; x<onlyDoTheseTables.length; x++)
onlyMap[ onlyDoTheseTables[x].toString() ] = true;
// For each table
var ts = document.getElementsByTagName("table");
for(var x=0; x<ts.length; x++) {
// In case null pointer when seeking anchor
try {
// If mem table
if( ts[x].id == "memTable" ) {
memTableCount++;
if( onlyDoTheseTables && ! onlyMap[memTableCount.toString()] )
continue;
var rs = ts[x].rows;
// If in progress, use backup
if( ts[x].s && ts[x].s.tbodyBackup )
rs = ts[x].s.tbodyBackup.rows;
// Add each row to the table
for(var z=1; z<rs.length; z++)
tb.appendChild( rs[z].cloneNode( true ) );
}
} catch(e) {}
}
// Append div
item.parentNode.appendChild( d )
// Start a session, using the 2nd "(memorize)" link
Mem.start( d.getElementsByTagName("A")[1] );
return false;
}
// Returns Y coord of top of element.
Mem.findY = function( o ) {
var curtop = 0;
if (o.offsetParent) {
curtop = o.offsetTop
while (o = o.offsetParent)
curtop += o.offsetTop
}
return curtop;
}
// Get distance from page top to window bottom
Mem.getWindowBottomY = function() {
// Get scrollY
var scrollY = document.body.scrollTop;
if( window.pageYOffset )
scrollY = window.pageYOffset
var winY = document.body.clientHeight;
if( window.innerHeight )
winY = window.innerHeight;
return scrollY + winY;
}
Mem.scrollDownIfNecessary = function( obj ) {
// If last row close to getting off-screen
if( this.findY( obj ) + 55 > this.getWindowBottomY() ) {
// Scroll down smoothly
var myInterval = window.setInterval(function () { window.scrollBy( 0, 2 ); }, 10);
window.setTimeout(function () { clearInterval(myInterval); },650);
}
}
Mem.startFirst = function(level) {
var as = byid('memTable').getElementsByTagName('a');
var a = as.length == 1 ? as[0] : as[1];
Mem.start( a );
// If 2, start another record
if(level == 2) {
Mem.showAnswer(this.tChile('showAnswer'), true);
Mem.answer(true, this.tChile('iWasRightButton'), true);
this.tChile('directionsDiv').cycles = 100;
}
}
Mem.parents = function(node, levels) {
for(x=1;x<=levels;x++) node = node.parentNode;
return node;
}
Mem.showOptions = function(node) {
this.setT(node);
this.tChile('optionsLink').style.display="none";
this.tChile('optionsBox').style.display="block";
Mem.t.s.optionsOn = true;
// Don't let clicking on options change default table
this.restoreTBody();
return false;
}
Mem.hideOptions = function(node) {
this.setT(node);
this.tChile('optionsLink').style.display="block";
this.tChile('optionsBox').style.display="none";
Mem.t.s.optionsOn = false;
// Don't let clicking on options change default table
this.restoreTBody();
return false;
}
Mem.close = function( node ) {
var t = this.setT( node );
// Don't re-open options
Mem.t.s.optionsOn = false;
Mem.restore();
// Invoke hook if reset
if(node != null) {
// In case method not there
try {
mem_close( t );
} catch(e) {}
}
return false;
}
Mem.finished = function() {
var directions = this.tChile('directionsDiv');
var buttons = this.tChile('buttons');
// Default values
directions.innerHTML = "<div style='text-align:center;'>Congratulations, you've finished.</div>";
buttons.innerHTML = "";
// Restore rows
this.addRowsFromBackup();
// Call hook
try {
mem_finished( [directions, buttons] );
} catch(e) {}
Mem.glow(2, "finished");
return false;
}
Mem.startOver = function( node ) {
var t = this.setT( node );
if( t.s.mode == "flashcard" )
Mem.start( t.getElementsByTagName('a')[t.s.column] );
else if( t.s.mode == "matching" )
Mem.startMatching( t );
return false;
}
Mem.startMatching = function( node ) {
var t = this.setT( node );
t.s.match0 = t.s.match1 = null;
// Change help text
this.tChile('mode').innerHTML = Mem.getModeDiv(1);
this.tChile('directionsDiv').innerHTML =
"<div style='text-align:center;'><b>Note:</b> this table has been <i style='font-weight:bold; color:#f90; cursor: pointer;'><span onclick='Mem.startOver(this);'>shuffled</span></i>. Click items to identify matches.</div>";
this.tChile('buttons').innerHTML = "";
this.tChile('progress').innerHTML = "";
var rows = t.rows;
// Add rows from backup
this.addRowsFromBackup();
// Format them
rows = t.rows;
for(var x=1; x<(rows.length-1); x++) {
var tds = rows[x].cells;
// Add click events
Mem.addEvent( tds[0], 'click', function(){ Mem.matchingClicked( this, 0 ) } );
Mem.addEvent( tds[1], 'click', function(){ Mem.matchingClicked( this, 1 ) } );
tds[0].style.cursor = tds[1].style.cursor = "pointer";
tds[0].style.background = tds[1].style.background = tds[0].style.endColor = tds[1].style.endColor = Mem.mGray;
// Add indexes
tds[0].mIndex = tds[1].mIndex = x;
}
// Shuffle columns
for (swaps=0; swaps<(rows.length*4); swaps++) {
Mem.swapOnce(rows,0);
Mem.swapOnce(rows,1);
}
this.glow(100);
t.s.mode = "matching";
return false;
}
Mem.matchingClicked = function(cell, side) {
// Exit if already correct
if(cell.mState == "correct")
return;
var t = this.setT( cell );
var rows = t.rows;
// Update colors of others, and count remaining
var remaining = 0;
for(var x=1; x<(rows.length-1); x++) {
var td = rows[x].cells[side];
// If gray, clear it
if((cell != td) && (td.mState == "guess")) {
td.mState = null;
td.style.background = td.endColor= Mem.mGray;
}
if(td.mState != "correct") remaining++;
}
// Remember this was clicked
if(side == 0) t.s.match0 = cell;
else t.s.match1 = cell;
// If already guessed
if(cell.mState == "guess") {
cell.mState = null;
cell.style.background = cell.endColor = Mem.mGray;
// Clear it
if(side == 0) t.s.match0 = null;
else t.s.match1 = null;
} else {
// Make it selected
cell.mState = "guess";
cell.style.background = cell.endColor = Mem.mClicked;
}
// Exit if neither are selected
if(! (t.s.match0 && t.s.match1))
return;
// Go through backup table and look for matches
var found = false;
var backupRows = t.s.tbodyBackup.getElementsByTagName('tr');
for(var x=1; x<backupRows.length; x++) {
var tds = backupRows[x].getElementsByTagName('td');
if((trim(t.s.match0.innerHTML) == trim(tds[0].innerHTML))
&& (trim(t.s.match1.innerHTML) == trim(tds[1].innerHTML)))
found = true;
}
// If match
if(found) {
var directions = this.tChile('directionsDiv');
if(directions.cycles > 2)
directions.cycles = 2;
// Make me dark green
t.s.match0.mState = t.s.match1.mState = "correct";
t.s.match0.endColor = t.s.match1.endColor = Mem.mGreen;
t.s.match0.style.cursor = t.s.match1.style.cursor = "";
// If finished - congrats message, restore rows
if(remaining == 1) {
directions.innerHTML = "<div style='text-align:center;'>Congratulations, you've finished. \
Try <a href='#' onclick='return Mem.flashcardMode(this)'>flashcard mode</a>.</div>";
Mem.glow(2, "finished");
this.addRowsFromBackup();
} else {
cell.style.background = Mem.mGray;
Mem.glow(1, "green", t.s.match0, Mem.mGreen);
Mem.glow(1, "green", t.s.match1, Mem.mGreen);
}
t.s.match0 = t.s.match1 = null;
return;
}
// Must not have been found
cell.style.background = Mem.mGray;
Mem.glow(1, "red", cell, Mem.mClicked);
}
Mem.swapOnce = function( rows, index ) {
var r1 = rows[Math.floor(Math.random() * (rows.length-2)) + 1];
var r2 = rows[Math.floor(Math.random() * (rows.length-2)) + 1];
var c1 = r1.cells[index];
r1.replaceChild(r2.cells[index], c1);
if(index == 0)
r2.insertBefore(c1, r2.cells[0]);
else
r2.appendChild(c1);
}
Mem.getModeDiv = function( index ) {
var r = "\
<span style='width:260px; text-align:right; padding: 0px 0px 2px 10px; letter-spacing:2px;\
border-left: solid #ccc 1px; \
border-bottom: solid #ccc 1px;'>\
";
var modes = [["flashcard mode", "return Mem.flashcardMode(this)"], ["matching mode", "return Mem.startMatching(this)"]];
for(var x=0; x<modes.length; x++) {
if( x > 0 ) r += " | ";
if(index == x)
r += "<b>" + modes[x][0] + "</b>";
else
r += "<a style='color:#aaa;' href='#' onclick=\"" + modes[x][1] + "\">" + modes[x][0] + "</a>";
}
r += "</span>";
return r;
}
Mem.getOptions = function() {
return "\
<div style='display:none; line-height:17px; margin:27px 6px 4px 6px; padding: 3px 4px 4px 20px; border:dashed #fc0 2px;' id=optionsBox>\
<a style='float:right; margin-top:-7px; font-size:9px;' href='#' onClick='return Mem.hideOptions(this)'>Hide Options</a>\
- <a target='_blank' href='http://memorizable.com/Help'>Help</a>\
- <a onclick='return Mem.startOver(this)' href='#'>Restart</a>\
- <a onclick='return Mem.close(this)' href='#'>Cancel</a>\
<br>\
- <a target='_blank' href='http://memorizable.com/About_Memorizable_Tables'>About Memorizable Tables</a>\
</div>\
";
}
Mem.setT = function(node) {
// Return current, if no change
if(! node)
return this.t;
// Remember last, for restoreTBody
if(( typeof( Mem.t ) == 'object'))
Mem.lastT = Mem.t;
// Climb up parent until we find table
while( ! node.isMem )
node = node.parentNode;
this.t = node;
return node;
}
Mem.lookupT = function(nodex) {
// Climb up parent until we find table
while(! nodex.isMem)
nodex = nodex.parentNode;
return nodex;
}
Mem.restoreTBody = function() {
Mem.t = Mem.lastT;
}
Mem.restore = function() {
var orig = Mem.t.s.tbodyBackup;
Mem.t.replaceChild( orig, Mem.t.tBodies[0] );
Mem.t = orig.parentNode;
// Whipe out ref to backup
Mem.t.s.tbodyBackup = null;
}
Mem.addRowsFromBackup = function() {
var t = this.t;
var rows = t.rows;
// Delete rows - except top and bottom
var length = rows.length;
for(var x=1; x<=length-2; x++)
t.tBodies[0].removeChild( rows[length - (x+1)] );
// Make copies from backup, add them to table
var bak = t.s.tbodyBackup.cloneNode( true );
var backupRows = bak.getElementsByTagName('tr');
var length = backupRows.length;
for(var x=1; x<length; x++)
t.tBodies[0].insertBefore( backupRows[1], rows[rows.length-1] );
}
Mem.glow = function(cycles, color, glowDiv, endColor) {
// Remember table
if(!glowDiv) {
glowDiv = this.tChile('directionsDiv');
// Do nothing if already going
if(glowDiv.cycles >= 1)
return;
}
glowDiv.cycles = cycles;
if(!endColor)
endColor = "#fff";
// Set end color to cell
glowDiv.endColor = endColor;
var glowLevel = color == "green" ? 35 : 0;
var glowIncrement = color == "red" ? 8 : 2;
if(color == "green") glowIncrement = 1;
var myInterval = window.setInterval(function () {
// Stop if cycles over
if(glowDiv.cycles <= 0) {
clearInterval(myInterval);
return;
}
// Change level
glowLevel += glowIncrement;
// Go darker
if(glowLevel < 0) {
glowIncrement = 2;
glowLevel += glowIncrement;
// If this is the end, set it to the end color
if(--glowDiv.cycles == 0) {
glowDiv.style.background = glowDiv.endColor;
return;
}
}
// Go lighter
if(glowLevel > 44) {
glowIncrement = -2;
glowLevel += glowIncrement;
if(glowDiv.cycles == 1) {
glowIncrement = color == "red" ? -6 : -1;
if(color == "green") glowIncrement = -6;
}
}
if(color == "red")
Mem.glowColor(glowDiv, glowLevel, 180, 1, -2, -2);
else if(color == "green")
Mem.glowColor(glowDiv, glowLevel, 255, -3, 0, -5);
else if(color == "finished")
Mem.glowColor(glowDiv, glowLevel, 255, -2, 0, -4);
else // Orange
Mem.glowColor(glowDiv, glowLevel, 255, 0, -1, -4);
}, 43);
}
Mem.glowColor = function(glowDiv, glowLevel, start, r, g, b) {
glowDiv.style.background = "rgb(" + (start+glowLevel*r) + "," + (start+glowLevel*g) + "," + (start+glowLevel*b) + ")";
}
Mem.chile = function(root, idName) {
var maybe = root.getElementsByTagName( '*' );
for(var x=0; x<maybe.length; x++)
if( maybe[x].id == idName )
return maybe[x];
}
Mem.tChile = function(idName) {
return this.chile(this.t, idName);
}
Mem.flashcardMode = function(node) {
Mem.setT(node);
return Mem.start( Mem.t.getElementsByTagName('a')[Mem.t.s.column] );
}
function trim( s ) {
return s.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}
function byid( key ) {
return document.getElementById( key );
}
Mem.addEvent( document, "keydown", Mem.keyWasPressed );
//}}}
Name: MptwBlack
Background: #000
Foreground: #fff
PrimaryPale: #333
PrimaryLight: #555
PrimaryMid: #888
PrimaryDark: #aaa
SecondaryPale: #111
SecondaryLight: #222
SecondaryMid: #555
SecondaryDark: #888
TertiaryPale: #222
TertiaryLight: #666
TertiaryMid: #888
TertiaryDark: #aaa
Error: #300
This is in progress. Help appreciated.
Name: MptwBlue
Background: #fff
Foreground: #000
PrimaryPale: #cdf
PrimaryLight: #57c
PrimaryMid: #114
PrimaryDark: #012
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/***
|Name:|MptwConfigPlugin|
|Description:|Miscellaneous tweaks used by MPTW|
|Version:|1.0 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#MptwConfigPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#MptwConfigPlugin|
!!Note: instead of editing this you should put overrides in MptwUserConfigPlugin
***/
//{{{
var originalReadOnly = readOnly;
var originalShowBackstage = showBackstage;
config.options.chkHttpReadOnly = false; // means web visitors can experiment with your site by clicking edit
readOnly = false; // needed because the above doesn't work any more post 2.1 (??)
showBackstage = true; // show backstage for same reason
config.options.chkInsertTabs = true; // tab inserts a tab when editing a tiddler
config.views.wikified.defaultText = ""; // don't need message when a tiddler doesn't exist
config.views.editor.defaultText = ""; // don't need message when creating a new tiddler
config.options.chkSaveBackups = true; // do save backups
config.options.txtBackupFolder = 'twbackup'; // put backups in a backups folder
config.options.chkAutoSave = (window.location.protocol == "file:"); // do autosave if we're in local file
config.mptwVersion = "2.5.3";
config.macros.mptwVersion={handler:function(place){wikify(config.mptwVersion,place);}};
if (config.options.txtTheme == '')
config.options.txtTheme = 'MptwTheme';
// add to default GettingStarted
config.shadowTiddlers.GettingStarted += "\n\nSee also [[MPTW]].";
// add select theme and palette controls in default OptionsPanel
config.shadowTiddlers.OptionsPanel = config.shadowTiddlers.OptionsPanel.replace(/(\n\-\-\-\-\nAlso see AdvancedOptions)/, "{{select{<<selectTheme>>\n<<selectPalette>>}}}$1");
// these are used by ViewTemplate
config.mptwDateFormat = 'DD/MM/YY';
config.mptwJournalFormat = 'Journal DD/MM/YY';
//}}}
Name: MptwGreen
Background: #fff
Foreground: #000
PrimaryPale: #9b9
PrimaryLight: #385
PrimaryMid: #031
PrimaryDark: #020
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
Name: MptwRed
Background: #fff
Foreground: #000
PrimaryPale: #eaa
PrimaryLight: #c55
PrimaryMid: #711
PrimaryDark: #500
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
|Name|MptwRounded|
|Description|Mptw Theme with some rounded corners (Firefox only)|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
|PageTemplate|MptwTheme##PageTemplate|
|StyleSheet|##StyleSheet|
!StyleSheet
/*{{{*/
[[MptwTheme##StyleSheet]]
.tiddler,
.sliderPanel,
.button,
.tiddlyLink,
.tabContents
{ -moz-border-radius: 1em; }
.tab {
-moz-border-radius-topleft: 0.5em;
-moz-border-radius-topright: 0.5em;
}
#topMenu {
-moz-border-radius-bottomleft: 2em;
-moz-border-radius-bottomright: 2em;
}
/*}}}*/
Name: MptwSmoke
Background: #fff
Foreground: #000
PrimaryPale: #aaa
PrimaryLight: #777
PrimaryMid: #111
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
|Name|MptwStandard|
|Description|Mptw Theme with the default TiddlyWiki PageLayout and Styles|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
Name: MptwTeal
Background: #fff
Foreground: #000
PrimaryPale: #B5D1DF
PrimaryLight: #618FA9
PrimaryMid: #1a3844
PrimaryDark: #000
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #f8f8f8
TertiaryLight: #bbb
TertiaryMid: #999
TertiaryDark: #888
Error: #f88
|Name|MptwTheme|
|Description|Mptw Theme including custom PageLayout|
|PageTemplate|##PageTemplate|
|ViewTemplate|##ViewTemplate|
|EditTemplate|##EditTemplate|
|StyleSheet|##StyleSheet|
http://mptw.tiddlyspot.com/#MptwTheme ($Rev: 1829 $)
!PageTemplate
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<!-- horizontal MainMenu -->
<div id='topMenu' refresh='content' tiddler='MainMenu'></div>
<!-- original MainMenu menu -->
<!-- <div id='mainMenu' refresh='content' tiddler='MainMenu'></div> -->
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div class='tiddler' id='hD' refresh='content' tiddler='contentHeader'></div>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
<div class='fD' id='fD' refresh='content' tiddler='contentFooter'></div>
</div>
<div style="position:fixed;z-index:1001;bottom:.1em;right:.1em;cursor:pointer;font-size:9pt;">
<a href="javascript:window.scrollTo(0,0)" title="scroll to top of page">▲</a>
</div>
<!--}}}-->
!ViewTemplate
<!--{{{-->
[[MptwTheme##ViewTemplateToolbar]]
<div class="tagglyTagged" macro="tags"></div>
<div class='titleContainer'>
<span class='title' macro='view title'></span>
<span macro="miniTag"></span>
</div>
<div class='subtitle'>
(updated <span macro='view modified date {{config.mptwDateFormat?config.mptwDateFormat:"MM/0DD/YY"}}'></span>
by <span macro='view modifier link'></span>)
<!--
(<span macro='message views.wikified.createdPrompt'></span>
<span macro='view created date {{config.mptwDateFormat?config.mptwDateFormat:"MM/0DD/YY"}}'></span>)
-->
</div>
<div macro="showWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
<div class='viewer'><pre macro='view text'></pre></div>
</div>
<div macro="else">
<div class='viewer' macro='view text wikified'></div>
</div>
<div class="tagglyTagging" macro="tagglyTagging"></div>
<!--}}}-->
!ViewTemplateToolbar
<!--{{{-->
<div class='toolbar'>
<span macro="showWhenTagged systemConfig">
<span macro="toggleTag systemConfigDisable . '[[disable|systemConfigDisable]]'"></span>
</span>
<span macro="showWhenTagged systemTheme"><span macro="applyTheme"></span></span>
<span macro="showWhenTagged systemPalette"><span macro="applyPalette"></span></span>
<span macro="showWhen tiddler.tags.contains('css') || tiddler.title == 'StyleSheet'"><span macro="refreshAll"></span></span>
<span style="padding:1em;"></span>
<span macro='toolbar closeTiddler closeOthers +editTiddler deleteTiddler > fields syncing permalink references jump'></span> <span macro='newHere label:"new here"'></span>
<span macro='newJournalHere {{config.mptwJournalFormat?config.mptwJournalFormat:"MM/0DD/YY"}}'></span>
</div>
<!--}}}-->
!EditTemplate
<!--{{{-->
<div class="toolbar" macro="toolbar +saveTiddler saveCloseTiddler closeOthers -cancelTiddler cancelCloseTiddler deleteTiddler"></div>
<div class="title" macro="view title"></div>
<div class="editLabel">Title</div><div class="editor" macro="edit title"></div>
<div macro='annotations'></div>
<div class="editLabel">Content</div><div class="editor" macro="edit text"></div>
<div class="editLabel">Tags</div><div class="editor" macro="edit tags"></div>
<div class="editorFooter"><span macro="message views.editor.tagPrompt"></span><span macro="tagChooser"></span></div>
<!--}}}-->
!StyleSheet
/*{{{*/
/* a contrasting background so I can see where one tiddler ends and the other begins */
body {
background: [[ColorPalette::TertiaryLight]];
}
/* sexy colours and font for the header */
.headerForeground {
color: [[ColorPalette::PrimaryPale]];
}
.headerShadow, .headerShadow a {
color: [[ColorPalette::PrimaryMid]];
}
/* separate the top menu parts */
.headerForeground, .headerShadow {
padding: 1em 1em 0;
}
.headerForeground, .headerShadow {
font-family: 'Trebuchet MS' sans-serif;
font-weight:bold;
}
.headerForeground .siteSubtitle {
color: [[ColorPalette::PrimaryLight]];
}
.headerShadow .siteSubtitle {
color: [[ColorPalette::PrimaryMid]];
}
/* make shadow go and down right instead of up and left */
.headerShadow {
left: 1px;
top: 1px;
}
/* prefer monospace for editing */
.editor textarea, .editor input {
font-family: 'Consolas' monospace;
background-color:[[ColorPalette::TertiaryPale]];
}
/* sexy tiddler titles */
.title {
font-size: 250%;
color: [[ColorPalette::PrimaryLight]];
font-family: 'Trebuchet MS' sans-serif;
}
/* more subtle tiddler subtitle */
.subtitle {
padding:0px;
margin:0px;
padding-left:1em;
font-size: 90%;
color: [[ColorPalette::TertiaryMid]];
}
.subtitle .tiddlyLink {
color: [[ColorPalette::TertiaryMid]];
}
/* a little bit of extra whitespace */
.viewer {
padding-bottom:3px;
}
/* don't want any background color for headings */
h1,h2,h3,h4,h5,h6 {
background-color: transparent;
color: [[ColorPalette::Foreground]];
}
/* give tiddlers 3d style border and explicit background */
.tiddler {
background: [[ColorPalette::Background]];
border-right: 2px [[ColorPalette::TertiaryMid]] solid;
border-bottom: 2px [[ColorPalette::TertiaryMid]] solid;
margin-bottom: 1em;
padding:1em 2em 2em 1.5em;
}
/* make options slider look nicer */
#sidebarOptions .sliderPanel {
border:solid 1px [[ColorPalette::PrimaryLight]];
}
/* the borders look wrong with the body background */
#sidebar .button {
border-style: none;
}
/* this means you can put line breaks in SidebarOptions for readability */
#sidebarOptions br {
display:none;
}
/* undo the above in OptionsPanel */
#sidebarOptions .sliderPanel br {
display:inline;
}
/* horizontal main menu stuff */
#displayArea {
margin: 1em 15.7em 0em 1em; /* use the freed up space */
}
#topMenu br {
display: none;
}
#topMenu {
background: [[ColorPalette::PrimaryMid]];
color:[[ColorPalette::PrimaryPale]];
}
#topMenu {
padding:2px;
}
#topMenu .button, #topMenu .tiddlyLink, #topMenu a {
margin-left: 0.5em;
margin-right: 0.5em;
padding-left: 3px;
padding-right: 3px;
color: [[ColorPalette::PrimaryPale]];
font-size: 115%;
}
#topMenu .button:hover, #topMenu .tiddlyLink:hover {
background: [[ColorPalette::PrimaryDark]];
}
/* make 2.2 act like 2.1 with the invisible buttons */
.toolbar {
visibility:hidden;
}
.selected .toolbar {
visibility:visible;
}
/* experimental. this is a little borked in IE7 with the button
* borders but worth it I think for the extra screen realestate */
.toolbar { float:right; }
/* fix for TaggerPlugin. from sb56637. improved by FND */
.popup li .tagger a {
display:inline;
}
/* makes theme selector look a little better */
#sidebarOptions .sliderPanel .select .button {
padding:0.5em;
display:block;
}
#sidebarOptions .sliderPanel .select br {
display:none;
}
/* make it print a little cleaner */
@media print {
#topMenu {
display: none ! important;
}
/* not sure if we need all the importants */
.tiddler {
border-style: none ! important;
margin:0px ! important;
padding:0px ! important;
padding-bottom:2em ! important;
}
.tagglyTagging .button, .tagglyTagging .hidebutton {
display: none ! important;
}
.headerShadow {
visibility: hidden ! important;
}
.tagglyTagged .quickopentag, .tagged .quickopentag {
border-style: none ! important;
}
.quickopentag a.button, .miniTag {
display: none ! important;
}
}
/* get user styles specified in StyleSheet */
[[StyleSheet]]
/*}}}*/
|Name|MptwTrim|
|Description|Mptw Theme with a reduced header to increase useful space|
|ViewTemplate|MptwTheme##ViewTemplate|
|EditTemplate|MptwTheme##EditTemplate|
|StyleSheet|MptwTheme##StyleSheet|
|PageTemplate|##PageTemplate|
!PageTemplate
<!--{{{-->
<!-- horizontal MainMenu -->
<div id='topMenu' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<span refresh='content' tiddler='SiteTitle' style="padding-left:1em;font-weight:bold;"></span>:
<span refresh='content' tiddler='MainMenu'></span>
</div>
<div id='sidebar'>
<div id='sidebarOptions'>
<div refresh='content' tiddler='SideBarOptions'></div>
<div style="margin-left:0.1em;"
macro='slider chkTabSliderPanel SideBarTabs {{"tabs \u00bb"}} "Show Timeline, All, Tags, etc"'></div>
</div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
For upgrading. See [[ImportTiddlers]].
URL: http://mptw.tiddlyspot.com/upgrade.html
/***
|Description:|A place to put your config tweaks so they aren't overwritten when you upgrade MPTW|
See http://www.tiddlywiki.org/wiki/Configuration_Options for other options you can set. In some cases where there are clashes with other plugins it might help to rename this to zzMptwUserConfigPlugin so it gets executed last.
***/
//{{{
// example: set your preferred date format
//config.mptwDateFormat = 'MM/0DD/YY';
//config.mptwJournalFormat = 'Journal MM/0DD/YY';
// example: set the theme you want to start with
//config.options.txtTheme = 'MptwRoundTheme';
config.options.txtTheme = 'MptwTrimTheme';
// example: switch off autosave, switch on backups and set a backup folder
//config.options.chkSaveBackups = true;
//config.options.chkAutoSave = false;
//config.options.txtBackupFolder = 'backups';
// uncomment to disable 'new means new' functionality for the new journal macro
//config.newMeansNewForJournalsToo = false;
//}}}
/***
|Name|NestedSlidersPlugin|
|Source|http://www.TiddlyTools.com/#NestedSlidersPlugin|
|Documentation|http://www.TiddlyTools.com/#NestedSlidersPluginInfo|
|Version|2.4.9|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Options|##Configuration|
|Description|show content in nest-able sliding/floating panels, without creating separate tiddlers for each panel's content|
!!!!!Documentation
>see [[NestedSlidersPluginInfo]]
!!!!!Configuration
<<<
<<option chkFloatingSlidersAnimate>> allow floating sliders to animate when opening/closing
>Note: This setting can cause 'clipping' problems in some versions of InternetExplorer.
>In addition, for floating slider animation to occur you must also allow animation in general (see [[AdvancedOptions]]).
<<<
!!!!!Revisions
<<<
2008.11.15 - 2.4.9 in adjustNestedSlider(), don't make adjustments if panel is marked as 'undocked' (CSS class). In onClickNestedSlider(), SHIFT-CLICK docks panel (see [[MoveablePanelPlugin]])
|please see [[NestedSlidersPluginInfo]] for additional revision details|
2005.11.03 - 1.0.0 initial public release. Thanks to RodneyGomes, GeoffSlocock, and PaulPetterson for suggestions and experiments.
<<<
!!!!!Code
***/
//{{{
version.extensions.NestedSlidersPlugin= {major: 2, minor: 4, revision: 9, date: new Date(2008,11,15)};
// options for deferred rendering of sliders that are not initially displayed
if (config.options.chkFloatingSlidersAnimate===undefined)
config.options.chkFloatingSlidersAnimate=false; // avoid clipping problems in IE
// default styles for 'floating' class
setStylesheet(".floatingPanel { position:absolute; z-index:10; padding:0.5em; margin:0em; \
background-color:#eee; color:#000; border:1px solid #000; text-align:left; }","floatingPanelStylesheet");
// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
window.removeCookie=function(name) {
document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;';
}
}
config.formatters.push( {
name: "nestedSliders",
match: "\\n?\\+{3}",
terminator: "\\s*\\={3}\\n?",
lookahead: "\\n?\\+{3}(\\+)?(\\([^\\)]*\\))?(\\!*)?(\\^(?:[^\\^\\*\\@\\[\\>]*\\^)?)?(\\*)?(\\@)?(?:\\{\\{([\\w]+[\\s\\w]*)\\{)?(\\[[^\\]]*\\])?(\\[[^\\]]*\\])?(?:\\}{3})?(\\#[^:]*\\:)?(\\>)?(\\.\\.\\.)?\\s*",
handler: function(w)
{
lookaheadRegExp = new RegExp(this.lookahead,"mg");
lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart)
{
var defopen=lookaheadMatch[1];
var cookiename=lookaheadMatch[2];
var header=lookaheadMatch[3];
var panelwidth=lookaheadMatch[4];
var transient=lookaheadMatch[5];
var hover=lookaheadMatch[6];
var buttonClass=lookaheadMatch[7];
var label=lookaheadMatch[8];
var openlabel=lookaheadMatch[9];
var panelID=lookaheadMatch[10];
var blockquote=lookaheadMatch[11];
var deferred=lookaheadMatch[12];
// location for rendering button and panel
var place=w.output;
// default to closed, no cookie, no accesskey, no alternate text/tip
var show="none"; var cookie=""; var key="";
var closedtext=">"; var closedtip="";
var openedtext="<"; var openedtip="";
// extra "+", default to open
if (defopen) show="block";
// cookie, use saved open/closed state
if (cookiename) {
cookie=cookiename.trim().slice(1,-1);
cookie="chkSlider"+cookie;
if (config.options[cookie]==undefined)
{ config.options[cookie] = (show=="block") }
show=config.options[cookie]?"block":"none";
}
// parse label/tooltip/accesskey: [label=X|tooltip]
if (label) {
var parts=label.trim().slice(1,-1).split("|");
closedtext=parts.shift();
if (closedtext.substr(closedtext.length-2,1)=="=")
{ key=closedtext.substr(closedtext.length-1,1); closedtext=closedtext.slice(0,-2); }
openedtext=closedtext;
if (parts.length) closedtip=openedtip=parts.join("|");
else { closedtip="show "+closedtext; openedtip="hide "+closedtext; }
}
// parse alternate label/tooltip: [label|tooltip]
if (openlabel) {
var parts=openlabel.trim().slice(1,-1).split("|");
openedtext=parts.shift();
if (parts.length) openedtip=parts.join("|");
else openedtip="hide "+openedtext;
}
var title=show=='block'?openedtext:closedtext;
var tooltip=show=='block'?openedtip:closedtip;
// create the button
if (header) { // use "Hn" header format instead of button/link
var lvl=(header.length>5)?5:header.length;
var btn = createTiddlyElement(createTiddlyElement(place,"h"+lvl,null,null,null),"a",null,buttonClass,title);
btn.onclick=onClickNestedSlider;
btn.setAttribute("href","javascript:;");
btn.setAttribute("title",tooltip);
}
else
var btn = createTiddlyButton(place,title,tooltip,onClickNestedSlider,buttonClass);
btn.innerHTML=title; // enables use of HTML entities in label
// set extra button attributes
btn.setAttribute("closedtext",closedtext);
btn.setAttribute("closedtip",closedtip);
btn.setAttribute("openedtext",openedtext);
btn.setAttribute("openedtip",openedtip);
btn.sliderCookie = cookie; // save the cookiename (if any) in the button object
btn.defOpen=defopen!=null; // save default open/closed state (boolean)
btn.keyparam=key; // save the access key letter ("" if none)
if (key.length) {
btn.setAttribute("accessKey",key); // init access key
btn.onfocus=function(){this.setAttribute("accessKey",this.keyparam);}; // **reclaim** access key on focus
}
btn.setAttribute("hover",hover?"true":"false");
btn.onmouseover=function(ev) {
// optional 'open on hover' handling
if (this.getAttribute("hover")=="true" && this.sliderPanel.style.display=='none') {
document.onclick.call(document,ev); // close transients
onClickNestedSlider(ev); // open this slider
}
// mouseover on button aligns floater position with button
if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this,this.sliderPanel);
}
// create slider panel
var panelClass=panelwidth?"floatingPanel":"sliderPanel";
if (panelID) panelID=panelID.slice(1,-1); // trim off delimiters
var panel=createTiddlyElement(place,"div",panelID,panelClass,null);
panel.button = btn; // so the slider panel know which button it belongs to
btn.sliderPanel=panel; // so the button knows which slider panel it belongs to
panel.defaultPanelWidth=(panelwidth && panelwidth.length>2)?panelwidth.slice(1,-1):"";
panel.setAttribute("transient",transient=="*"?"true":"false");
panel.style.display = show;
panel.style.width=panel.defaultPanelWidth;
panel.onmouseover=function(event) // mouseover on panel aligns floater position with button
{ if (window.adjustSliderPos) window.adjustSliderPos(this.parentNode,this.button,this); }
// render slider (or defer until shown)
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
if ((show=="block")||!deferred) {
// render now if panel is supposed to be shown or NOT deferred rendering
w.subWikify(blockquote?createTiddlyElement(panel,"blockquote"):panel,this.terminator);
// align floater position with button
if (window.adjustSliderPos) window.adjustSliderPos(place,btn,panel);
}
else {
var src = w.source.substr(w.nextMatch);
var endpos=findMatchingDelimiter(src,"+++","===");
panel.setAttribute("raw",src.substr(0,endpos));
panel.setAttribute("blockquote",blockquote?"true":"false");
panel.setAttribute("rendered","false");
w.nextMatch += endpos+3;
if (w.source.substr(w.nextMatch,1)=="\n") w.nextMatch++;
}
}
}
}
)
function findMatchingDelimiter(src,starttext,endtext) {
var startpos = 0;
var endpos = src.indexOf(endtext);
// check for nested delimiters
while (src.substring(startpos,endpos-1).indexOf(starttext)!=-1) {
// count number of nested 'starts'
var startcount=0;
var temp = src.substring(startpos,endpos-1);
var pos=temp.indexOf(starttext);
while (pos!=-1) { startcount++; pos=temp.indexOf(starttext,pos+starttext.length); }
// set up to check for additional 'starts' after adjusting endpos
startpos=endpos+endtext.length;
// find endpos for corresponding number of matching 'ends'
while (startcount && endpos!=-1) {
endpos = src.indexOf(endtext,endpos+endtext.length);
startcount--;
}
}
return (endpos==-1)?src.length:endpos;
}
//}}}
//{{{
window.onClickNestedSlider=function(e)
{
if (!e) var e = window.event;
var theTarget = resolveTarget(e);
while (theTarget && theTarget.sliderPanel==undefined) theTarget=theTarget.parentNode;
if (!theTarget) return false;
var theSlider = theTarget.sliderPanel;
var isOpen = theSlider.style.display!="none";
// if SHIFT-CLICK, dock panel first (see [[MoveablePanelPlugin]])
if (e.shiftKey && config.macros.moveablePanel) config.macros.moveablePanel.dock(theSlider,e);
// toggle label
theTarget.innerHTML=isOpen?theTarget.getAttribute("closedText"):theTarget.getAttribute("openedText");
// toggle tooltip
theTarget.setAttribute("title",isOpen?theTarget.getAttribute("closedTip"):theTarget.getAttribute("openedTip"));
// deferred rendering (if needed)
if (theSlider.getAttribute("rendered")=="false") {
var place=theSlider;
if (theSlider.getAttribute("blockquote")=="true")
place=createTiddlyElement(place,"blockquote");
wikify(theSlider.getAttribute("raw"),place);
theSlider.setAttribute("rendered","true");
}
// show/hide the slider
if(config.options.chkAnimate && (!hasClass(theSlider,'floatingPanel') || config.options.chkFloatingSlidersAnimate))
anim.startAnimating(new Slider(theSlider,!isOpen,e.shiftKey || e.altKey,"none"));
else
theSlider.style.display = isOpen ? "none" : "block";
// reset to default width (might have been changed via plugin code)
theSlider.style.width=theSlider.defaultPanelWidth;
// align floater panel position with target button
if (!isOpen && window.adjustSliderPos) window.adjustSliderPos(theSlider.parentNode,theTarget,theSlider);
// if showing panel, set focus to first 'focus-able' element in panel
if (theSlider.style.display!="none") {
var ctrls=theSlider.getElementsByTagName("*");
for (var c=0; c<ctrls.length; c++) {
var t=ctrls[c].tagName.toLowerCase();
if ((t=="input" && ctrls[c].type!="hidden") || t=="textarea" || t=="select")
{ try{ ctrls[c].focus(); } catch(err){;} break; }
}
}
var cookie=theTarget.sliderCookie;
if (cookie && cookie.length) {
config.options[cookie]=!isOpen;
if (config.options[cookie]!=theTarget.defOpen) window.saveOptionCookie(cookie);
else window.removeCookie(cookie); // remove cookie if slider is in default display state
}
// prevent SHIFT-CLICK from being processed by browser (opens blank window... yuck!)
// prevent clicks *within* a slider button from being processed by browser
// but allow plain click to bubble up to page background (to close transients, if any)
if (e.shiftKey || theTarget!=resolveTarget(e))
{ e.cancelBubble=true; if (e.stopPropagation) e.stopPropagation(); }
Popup.remove(); // close open popup (if any)
return false;
}
//}}}
//{{{
// click in document background closes transient panels
document.nestedSliders_savedOnClick=document.onclick;
document.onclick=function(ev) { if (!ev) var ev=window.event; var target=resolveTarget(ev);
if (document.nestedSliders_savedOnClick)
var retval=document.nestedSliders_savedOnClick.apply(this,arguments);
// if click was inside a popup... leave transient panels alone
var p=target; while (p) if (hasClass(p,"popup")) break; else p=p.parentNode;
if (p) return retval;
// if click was inside transient panel (or something contained by a transient panel), leave it alone
var p=target; while (p) {
if ((hasClass(p,"floatingPanel")||hasClass(p,"sliderPanel"))&&p.getAttribute("transient")=="true") break;
p=p.parentNode;
}
if (p) return retval;
// otherwise, find and close all transient panels...
var all=document.all?document.all:document.getElementsByTagName("DIV");
for (var i=0; i<all.length; i++) {
// if it is not a transient panel, or the click was on the button that opened this panel, don't close it.
if (all[i].getAttribute("transient")!="true" || all[i].button==target) continue;
// otherwise, if the panel is currently visible, close it by clicking it's button
if (all[i].style.display!="none") window.onClickNestedSlider({target:all[i].button})
if (!hasClass(all[i],"floatingPanel")&&!hasClass(all[i],"sliderPanel")) all[i].style.display="none";
}
return retval;
};
//}}}
//{{{
// adjust floating panel position based on button position
if (window.adjustSliderPos==undefined) window.adjustSliderPos=function(place,btn,panel) {
if (hasClass(panel,"floatingPanel") && !hasClass(panel,"undocked")) {
// see [[MoveablePanelPlugin]] for use of 'undocked'
var rightEdge=document.body.offsetWidth-1;
var panelWidth=panel.offsetWidth;
var left=0;
var top=btn.offsetHeight;
if (place.style.position=="relative" && findPosX(btn)+panelWidth>rightEdge) {
left-=findPosX(btn)+panelWidth-rightEdge; // shift panel relative to button
if (findPosX(btn)+left<0) left=-findPosX(btn); // stay within left edge
}
if (place.style.position!="relative") {
var left=findPosX(btn);
var top=findPosY(btn)+btn.offsetHeight;
var p=place; while (p && !hasClass(p,'floatingPanel')) p=p.parentNode;
if (p) { left-=findPosX(p); top-=findPosY(p); }
if (left+panelWidth>rightEdge) left=rightEdge-panelWidth;
if (left<0) left=0;
}
panel.style.left=left+"px"; panel.style.top=top+"px";
}
}
//}}}
//{{{
// TW2.1 and earlier:
// hijack Slider stop handler so overflow is visible after animation has completed
Slider.prototype.coreStop = Slider.prototype.stop;
Slider.prototype.stop = function()
{ this.coreStop.apply(this,arguments); this.element.style.overflow = "visible"; }
// TW2.2+
// hijack Morpher stop handler so sliderPanel/floatingPanel overflow is visible after animation has completed
if (version.major+.1*version.minor+.01*version.revision>=2.2) {
Morpher.prototype.coreStop = Morpher.prototype.stop;
Morpher.prototype.stop = function() {
this.coreStop.apply(this,arguments);
var e=this.element;
if (hasClass(e,"sliderPanel")||hasClass(e,"floatingPanel")) {
// adjust panel overflow and position after animation
e.style.overflow = "visible";
if (window.adjustSliderPos) window.adjustSliderPos(e.parentNode,e.button,e);
}
};
}
//}}}
/***
|Name:|NewHerePlugin|
|Description:|Creates the new here and new journal macros|
|Version:|3.0 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#NewHerePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.macros, {
newHere: {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
wikify("<<newTiddler "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
}
},
newJournalHere: {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
wikify("<<newJournal "+paramString+" tag:[["+tiddler.title+"]]>>",place,null,tiddler);
}
}
});
//}}}
/***
|Name:|NewMeansNewPlugin|
|Description:|If 'New Tiddler' already exists then create 'New Tiddler (1)' and so on|
|Version:|1.1.1 ($Rev: 2263 $)|
|Date:|$Date: 2007-06-13 04:22:32 +1000 (Wed, 13 Jun 2007) $|
|Source:|http://mptw.tiddlyspot.com/empty.html#NewMeansNewPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Note: I think this should be in the core
***/
//{{{
// change this or set config.newMeansNewForJournalsToo it in MptwUuserConfigPlugin
if (config.newMeansNewForJournalsToo == undefined) config.newMeansNewForJournalsToo = true;
String.prototype.getNextFreeName = function() {
var numberRegExp = / \(([0-9]+)\)$/;
var match = numberRegExp.exec(this);
if (match) {
var num = parseInt(match[1]) + 1;
return this.replace(numberRegExp," ("+num+")");
}
else {
return this + " (1)";
}
}
config.macros.newTiddler.checkForUnsaved = function(newName) {
var r = false;
story.forEachTiddler(function(title,element) {
if (title == newName)
r = true;
});
return r;
}
config.macros.newTiddler.getName = function(newName) {
while (store.getTiddler(newName) || config.macros.newTiddler.checkForUnsaved(newName))
newName = newName.getNextFreeName();
return newName;
}
config.macros.newTiddler.onClickNewTiddler = function()
{
var title = this.getAttribute("newTitle");
if(this.getAttribute("isJournal") == "true") {
title = new Date().formatString(title.trim());
}
// ---- these three lines should be the only difference between this and the core onClickNewTiddler
if (config.newMeansNewForJournalsToo || this.getAttribute("isJournal") != "true")
title = config.macros.newTiddler.getName(title);
var params = this.getAttribute("params");
var tags = params ? params.split("|") : [];
var focus = this.getAttribute("newFocus");
var template = this.getAttribute("newTemplate");
var customFields = this.getAttribute("customFields");
if(!customFields && !store.isShadowTiddler(title))
customFields = String.encodeHashMap(config.defaultCustomFields);
story.displayTiddler(null,title,template,false,null,null);
var tiddlerElem = story.getTiddler(title);
if(customFields)
story.addCustomFields(tiddlerElem,customFields);
var text = this.getAttribute("newText");
if(typeof text == "string")
story.getTiddlerField(title,"text").value = text.format([title]);
for(var t=0;t<tags.length;t++)
story.setTiddlerTag(title,tags[t],+1);
story.focusTiddler(title,focus);
return false;
};
//}}}
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='ContentsSlider'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
/***
|''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"
});
*/
//}}}
{{intro{Log the various posts to TiddlyWikiUsr group}}}
!!! May 24, 2009
Hello
I am using the MPTW with the MptwTheme to get the horizontal MainMenu. I am using {{{@@padding-left:25em;<<search>>@@ @@padding-left:1em; <<tiddler ToggleRightSidebar>>@@}}} to offset the search box and the toggle sidebar to the right.
My question is how to move the search box and ToggleRightSidebar to be all the way to the right (right aligned?) for any given page width? For an example please see http://mptwcadfael.tiddlyspot.com/.
Thanks
Wumpus
/***
|Name:|PrettyDatesPlugin|
|Description:|Provides a new date format ('pppp') that displays times such as '2 days ago'|
|Version:|1.0 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#PrettyDatesPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Notes
* If you want to you can rename this plugin. :) Some suggestions: LastUpdatedPlugin, RelativeDatesPlugin, SmartDatesPlugin, SexyDatesPlugin.
* Inspired by http://ejohn.org/files/pretty.js
***/
//{{{
Date.prototype.prettyDate = function() {
var diff = (((new Date()).getTime() - this.getTime()) / 1000);
var day_diff = Math.floor(diff / 86400);
if (isNaN(day_diff)) return "";
else if (diff < 0) return "in the future";
else if (diff < 60) return "just now";
else if (diff < 120) return "1 minute ago";
else if (diff < 3600) return Math.floor(diff/60) + " minutes ago";
else if (diff < 7200) return "1 hour ago";
else if (diff < 86400) return Math.floor(diff/3600) + " hours ago";
else if (day_diff == 1) return "Yesterday";
else if (day_diff < 7) return day_diff + " days ago";
else if (day_diff < 14) return "a week ago";
else if (day_diff < 31) return Math.ceil(day_diff/7) + " weeks ago";
else if (day_diff < 62) return "a month ago";
else if (day_diff < 365) return "about " + Math.ceil(day_diff/31) + " months ago";
else if (day_diff < 730) return "a year ago";
else return Math.ceil(day_diff/365) + " years ago";
}
Date.prototype.formatString_orig_mptw = Date.prototype.formatString;
Date.prototype.formatString = function(template) {
return this.formatString_orig_mptw(template).replace(/pppp/,this.prettyDate());
}
// for MPTW. otherwise edit your ViewTemplate as required.
// config.mptwDateFormat = 'pppp (DD/MM/YY)';
config.mptwDateFormat = 'pppp';
//}}}
/***
|Name:|QuickOpenTagPlugin|
|Description:|Changes tag links to make it easier to open tags as tiddlers|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#QuickOpenTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
config.quickOpenTag = {
dropdownChar: (document.all ? "\u25bc" : "\u25be"), // the little one doesn't work in IE?
createTagButton: function(place,tag,excludeTiddler) {
// little hack so we can do this: <<tag PrettyTagName|RealTagName>>
var splitTag = tag.split("|");
var pretty = tag;
if (splitTag.length == 2) {
tag = splitTag[1];
pretty = splitTag[0];
}
var sp = createTiddlyElement(place,"span",null,"quickopentag");
createTiddlyText(createTiddlyLink(sp,tag,false),pretty);
var theTag = createTiddlyButton(sp,config.quickOpenTag.dropdownChar,
config.views.wikified.tag.tooltip.format([tag]),onClickTag);
theTag.setAttribute("tag",tag);
if (excludeTiddler)
theTag.setAttribute("tiddler",excludeTiddler);
return(theTag);
},
miniTagHandler: function(place,macroName,params,wikifier,paramString,tiddler) {
var tagged = store.getTaggedTiddlers(tiddler.title);
if (tagged.length > 0) {
var theTag = createTiddlyButton(place,config.quickOpenTag.dropdownChar,
config.views.wikified.tag.tooltip.format([tiddler.title]),onClickTag);
theTag.setAttribute("tag",tiddler.title);
theTag.className = "miniTag";
}
},
allTagsHandler: function(place,macroName,params) {
var tags = store.getTags(params[0]);
var filter = params[1]; // new feature
var ul = createTiddlyElement(place,"ul");
if(tags.length == 0)
createTiddlyElement(ul,"li",null,"listTitle",this.noTags);
for(var t=0; t<tags.length; t++) {
var title = tags[t][0];
if (!filter || (title.match(new RegExp('^'+filter)))) {
var info = getTiddlyLinkInfo(title);
var theListItem =createTiddlyElement(ul,"li");
var theLink = createTiddlyLink(theListItem,tags[t][0],true);
var theCount = " (" + tags[t][1] + ")";
theLink.appendChild(document.createTextNode(theCount));
var theDropDownBtn = createTiddlyButton(theListItem," " +
config.quickOpenTag.dropdownChar,this.tooltip.format([tags[t][0]]),onClickTag);
theDropDownBtn.setAttribute("tag",tags[t][0]);
}
}
},
// todo fix these up a bit
styles: [
"/*{{{*/",
"/* created by QuickOpenTagPlugin */",
".tagglyTagged .quickopentag, .tagged .quickopentag ",
" { margin-right:1.2em; border:1px solid #eee; padding:2px; padding-right:0px; padding-left:1px; }",
".quickopentag .tiddlyLink { padding:2px; padding-left:3px; }",
".quickopentag a.button { padding:1px; padding-left:2px; padding-right:2px;}",
"/* extra specificity to make it work right */",
"#displayArea .viewer .quickopentag a.button, ",
"#displayArea .viewer .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink, ",
"#mainMenu .quickopentag a.tiddyLink ",
" { border:0px solid black; }",
"#displayArea .viewer .quickopentag a.button, ",
"#mainMenu .quickopentag a.button ",
" { margin-left:0px; padding-left:2px; }",
"#displayArea .viewer .quickopentag a.tiddlyLink, ",
"#mainMenu .quickopentag a.tiddlyLink ",
" { margin-right:0px; padding-right:0px; padding-left:0px; margin-left:0px; }",
"a.miniTag {font-size:150%;} ",
"#mainMenu .quickopentag a.button ",
" /* looks better in right justified main menus */",
" { margin-left:0px; padding-left:2px; margin-right:0px; padding-right:0px; }",
"#topMenu .quickopentag { padding:0px; margin:0px; border:0px; }",
"#topMenu .quickopentag .tiddlyLink { padding-right:1px; margin-right:0px; }",
"#topMenu .quickopentag .button { padding-left:1px; margin-left:0px; border:0px; }",
"/*}}}*/",
""].join("\n"),
init: function() {
// we fully replace these builtins. can't hijack them easily
window.createTagButton = this.createTagButton;
config.macros.allTags.handler = this.allTagsHandler;
config.macros.miniTag = { handler: this.miniTagHandler };
config.shadowTiddlers["QuickOpenTagStyles"] = this.styles;
store.addNotification("QuickOpenTagStyles",refreshStyles);
}
}
config.quickOpenTag.init();
//}}}
"If you look for the truth outside of yourself it gets farther and farther away. Yet, when you achieve that perfect harmony of mind and body and can control your Ki, the results is a great spirtual awakening ... " {{hint{Master Tung Shen -- 9th Century Philosopher}}}
----
"A strong man conquers others, while a great warrior conquers himself. {{hint{Ancient Sage}}}
----
"Small men speak rash words and act inconsistently. Mediocre men focus only on one weapon or technique. True warriors use all skills, share with their brothers, learn from their betters, and understand all things for their improvement." {{hint{King Sejong}}}
----
"The only time we fail is when we stop trying."
----
"The only limitations we have are the ones that we place on ourselves..."
----
"Learn the ways to preserve rather than destroy. Avoid rather than check, check rather than hurt, hurt rather than maim, maim rather than kill ... for all life is precious nor can any be replaced." {{hint{Ancient Shaolin code of reaction}}}
----
"The Martial Artist in his completeness as a rational, volitional being, as well as one who is sentient and appetive, can effect the realization of his higher self in any way otherwise unattainable. To become a true warrior in any Martial Art, as in the combat of life, is his unswerving endeavor. The principles of the Martial Arts thus merge with the principals of life itself." {{hint{Grandmaster Sang Kyu Shim}}}
----
The tighter you squeeze, the less you have. [Zen Saying]
----
We cannot see our reflection in running water. It is only in still water that we can see. [Taoist Proverb]
----
When his students came to him and asked how he could be happy in a world of such impermanence, the master held up a glass and said, "For me, this glass is already broken. I enjoy it; I drink out of it. But when I put this glass on a shelf and my elbow brushes it and it falls to the ground and shatters, I say, 'Of course.' When I understand that this glass is already broken, every moment with it is precious." [Achaan Chaa]
----
Just think of the trees: they let the birds perch and fly, with no intention to call them when they come and no longing for their return when they fly away. If people's hearts can be like the trees, they will not be off the Way. [Zen Quotes by Langya]
----
You must have been warned against letting the golden hours slip by; but some of them are golden only because we let them slip by. [James M. Barrie]
----
Water which is too pure has no fish. [Ts’ai Ken T’an]
----
The quieter you become, the more you are able to hear.
----
We shape clay into a pot, but it is the emptiness inside that holds whatever we want. [Lao Tzu]
----
When you are deluded and full of doubt, even a thousand books of scripture are not enough.
When you have realized understanding, even one word is too much. [Fen-Yang.]
----
Enlightenment is like the moon reflected on the water. The moon does not get wet, nor is the water broken. Although its light is wide and great, the moon is reflected even in a puddle an inch wide. The whole moon and the entire sky are reflected in one dewdrop on the grass. [Dogen.]
----
If you cannot find the truth right where you are where else do you expect to find it? [Dogen Zenji]
----
The obstacle is the path [Zen proverb]
----
A flower falls even though we love it and a weed grows even though we do not love it [Dogen Zenji]
----
One moon shows in every pool in every pool the one moon [Zen Forest Saying]
----
The world is like a mirror you see? smile and your friends smile back [Japanese Zen saying]
----
So an ancient once said, "Accept the anxieties and difficulties of this life". Don't expect your practice to be clear of obstacles. Without hindrances the mind that seeks enlightenment may be burnt out. So an ancient once said, "Attain deliverance in disturbances". [Zen Master Kyong Ho (1849-1912)]
----
A master in the art of living draws no sharp distinction between his work and his play; his labor and his leisure; his mind and his body; his education and his recreation. He hardly knows which is which. He simply pursues his vision of excellence through whatever he is doing, and leaves others to determine whether he is working or playing. To himself, he always appears to be doing both. [Francoise Rene Auguste Chateaubriand]
----
If you understand, things are just as they are; if you do not understand, things are just as they are. [Zen proverb]
---
I have discovered that all of mans unhappiness derives from only one source, not being able to sit quietly in a room [Blaise Pascal]
----
We do not learn by experience, but by our capacity for experience [Buddha]
----
I long to accomplish a great and noble task; but it is my chief duty to accomplish small tasks as if they were great and noble. Hellen Keller]]
----
To get rid of your passions is not Nirvana; to look upon them as no matter of yours, that is nirvana. [Anonymous]
----
Have good trust in yourself -- not in the One that you think you should be, but in the One that you are [Maezumi Roshi]
----
We would never learn to be brave and patient if there were only joy in the world. [Hellen Keller]
----
In your hopelessness is the only hope, and in your desirelessness is your only fulfillment, and in your tremendous helplessness suddenly the whole existence starts helping you. [Osho]
----
Our life is shaped by our mind; we become what we think. Suffering follows an evil thought as the wheels of a cart follow the oxen that draws it. Our life is shaped by our mind; we become what we think. Joy follows a pure thought like a shadow that never leaves. [The Buddha]
----
One who conquers himself is greater than another who conquers a thousand times a thousand on the battlefield. [The Buddha]
----
Many persons have a wrong idea of what constitutes true happiness. It is not attained through self-gratification but through fidelity to a worthy purpose [Helen Keller]
/***
|Name|QuoteOfTheDayPlugin|
|Source|http://www.TiddlyTools.com/#QuoteOfTheDayPlugin|
|Documentation|http://www.TiddlyTools.com/#QuoteOfTheDayPluginInfo|
|Version|1.4.1|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|Display a randomly selected "quote of the day" from a list defined in a separate tiddler|
!!!!!Documentation
>see [[QuoteOfTheDayPluginInfo]]
!!!!!Revisions
<<<
2008.03.21 [1.4.1] in showNextItem(), corrected handling for random selection so that //initial// index value will randomized correctly instead of always showing first item, even when randomizing. Thanks to Riccardo Gherardi for finding this.
| Please see [[QuoteOfTheDayPluginInfo]] for previous revision details |
2005.10.21 [1.0.0] Initial Release. Based on a suggestion by M.Russula
<<<
!!!!!Code
***/
//{{{
version.extensions.QuoteOfTheDayPlugin= {major: 1, minor: 4, revision: 1, date: new Date(2008,3,21)};
config.macros.QOTD = {
clickTooltip: "click to view another item",
timerTooltip: "auto-timer stopped... 'mouseout' to restart timer",
timerClickTooltip: "auto-timer stopped... click to view another item, or 'mouseout' to restart timer",
handler:
function(place,macroName,params) {
var tid=params.shift(); // source tiddler containing HR-separated quotes
var p=params.shift();
var click=true; // allow click for next item
var inline=false; // wrap in slider for animation effect
var random=true; // pick an item at random (default for "quote of the day" usage)
var folder=false; // use local filesystem folder list
var cookie=""; // default to no cookie
var next=0; // default to first item (or random item)
while (p) {
if (p.toLowerCase()=="noclick") var click=false;
if (p.toLowerCase()=="inline") var inline=true;
if (p.toLowerCase()=="norandom") var random=false;
if (p.toLowerCase().substr(0,7)=="cookie:") var cookie=p.substr(8);
if (!isNaN(p)) var delay=p;
p=params.shift();
}
if ((click||delay) && !inline) {
var panel = createTiddlyElement(null,"div",null,"sliderPanel");
panel.style.display="none";
place.appendChild(panel);
var here=createTiddlyElement(panel,click?"a":"span",null,"QOTD");
}
else
var here=createTiddlyElement(place,click?"a":"span",null,"QOTD");
here.id=(new Date()).convertToYYYYMMDDHHMMSSMMM()+Math.random().toString(); // unique ID
// get items from tiddler or file list
var list=store.getTiddlerText(tid,"");
if (!list||!list.length) { // not a tiddler... maybe an image directory?
var list=this.getImageFileList(tid);
if (!list.length) { // maybe relative path... fixup and try again
var h=document.location.href;
var p=getLocalPath(decodeURIComponent(h.substr(0,h.lastIndexOf("/")+1)));
var list=this.getImageFileList(p+tid);
}
}
if (!list||!list.length) return false; // no contents... nothing to display!
here.setAttribute("list",list);
if (delay) here.setAttribute("delay",delay);
here.setAttribute("random",random);
here.setAttribute("cookie",cookie);
if (click) {
here.title=this.clickTooltip
if (!inline) here.style.display="block";
here.setAttribute("href","javascript:;");
here.onclick=function(event)
{ config.macros.QOTD.showNextItem(this); }
}
if (config.options["txtQOTD_"+cookie]!=undefined) next=parseInt(config.options["txtQOTD_"+cookie]);
here.setAttribute("nextItem",next);
config.macros.QOTD.showNextItem(here);
if (delay) {
here.title=click?this.timerClickTooltip:this.timerTooltip
here.onmouseover=function(event)
{ clearTimeout(this.ticker); };
here.onmouseout=function(event)
{ this.ticker=setTimeout("config.macros.QOTD.tick('"+this.id+"')",this.getAttribute("delay")); };
here.ticker=setTimeout("config.macros.QOTD.tick('"+here.id+"')",delay);
}
},
tick: function(id) {
var here=document.getElementById(id); if (!here) return;
config.macros.QOTD.showNextItem(here);
here.ticker=setTimeout("config.macros.QOTD.tick('"+id+"')",here.getAttribute("delay"));
},
showNextItem:
function (here) {
// hide containing slider panel (if any)
var p=here.parentNode;
if (p.className=="sliderPanel") p.style.display = "none"
// get a new quote
var index=here.getAttribute("nextItem");
var items=here.getAttribute("list").split("\n----\n");
if (index<0||index>=items.length) index=0;
if (here.getAttribute("random")=="true") index=Math.floor(Math.random()*items.length);
var txt=items[index];
// re-render quote display element, and advance index counter
removeChildren(here); wikify(txt,here);
index++; here.setAttribute("nextItem",index);
var cookie=here.getAttribute("cookie");
if (cookie.length) {
config.options["txtQOTD_"+cookie]=index.toString();
saveOptionCookie("txtQOTD_"+cookie);
}
// redisplay slider panel (if any)
if (p.className=="sliderPanel") {
if(anim && config.options.chkAnimate)
anim.startAnimating(new Slider(p,true,false,"none"));
else p.style.display="block";
}
},
getImageFileList: function(cwd) { // returns HR-separated list of image files
function isImage(fn) {
var ext=fn.substr(fn.length-3,3).toLowerCase();
return ext=="jpg"||ext=="gif"||ext=="png";
}
var files=[];
if (config.browser.isIE) {
cwd=cwd.replace(/\//g,"\\");
// IE uses ActiveX to read filesystem info
var fso = new ActiveXObject("Scripting.FileSystemObject");
if(!fso.FolderExists(cwd)) return [];
var dir=fso.GetFolder(cwd);
for(var f=new Enumerator(dir.Files); !f.atEnd(); f.moveNext())
if (isImage(f.item().path)) files.push("[img[%0]]".format(["file:///"+f.item().path.replace(/\\/g,"/")]));
} else {
// FireFox (mozilla) uses "components" to read filesystem info
// get security access
if(!window.Components) return;
try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
catch(e) { alert(e.description?e.description:e.toString()); return []; }
// open/validate directory
var file=Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
try { file.initWithPath(cwd); } catch(e) { return []; }
if (!file.exists() || !file.isDirectory()) { return []; }
var folder=file.directoryEntries;
while (folder.hasMoreElements()) {
var f=folder.getNext().QueryInterface(Components.interfaces.nsILocalFile);
if (f instanceof Components.interfaces.nsILocalFile)
if (isImage(f.path)) files.push("[img[%0]]".format(["file:///"+f.path.replace(/\\/g,"/")]));
}
}
return files.join("\n----\n");
}
}
//}}}
/***
|''Name:''|ReminderPlugin|
|''Version:''|2.3.10 (Jun 28, 2007)|
|''Source:''|http://remindermacros.tiddlyspot.com|
|''Author:''|Jeremy Sheeley(pop1280 [at] excite [dot] com)<<br>>Maintainer: simon.baird@gmail.com|
|''Licence:''|[[BSD open source license]]|
|''Macros:''|reminder, showreminders, displayTiddlersWithReminders, newReminder|
|''TiddlyWiki:''|2.0+|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Description
This plugin provides macros for tagging a date with a reminder. Use the {{{reminder}}} macro to do this. The {{{showReminders}}} and {{{displayTiddlersWithReminder}}} macros automatically search through all available tiddlers looking for upcoming reminders.
!Installation
* Create a new tiddler in your tiddlywiki titled ReminderPlugin and give it the {{{systemConfig}}} tag. The tag is important because it tells TW that this is executable code.
* Double click this tiddler, and copy all the text from the tiddler's body.
* Paste the text into the body of the new tiddler in your TW.
* Save and reload your TW.
* You can copy some examples into your TW as well. See [[Simple examples]], [[Holidays]], [[showReminders]] and [[Personal Reminders]]
!Syntax:
|>|See [[ReminderSyntax]] and [[showRemindersSyntax]]|
!Revision history
* v2.3.10 (Jun 28, 2007)
** Removed window.story = window backwards compatibility hacks since they were breaking TW 2.2
* v2.3.9 (Apr 26, 2007)
** allow bracketed list format in tags param lets you use tags with spaces
* v2.3.8 (Mar 9, 2006)
**Bug fix: A global variable had snuck in, which was killing FF 1.5.0.1
**Feature: You can now use TIDDLER and TIDDLERNAME in a regular reminder format
* v2.3.6 (Mar 1, 2006)
**Bug fix: Reminders for today weren't being matched sometimes.
**Feature: Solidified integration with DatePlugin and CalendarPlugin
**Feature: Recurring reminders will now return multiple hits in showReminders and the calendar.
**Feature: Added TIDDLERNAME to the replacements for showReminders format, for plugins that need the title without brackets.
* v2.3.5 (Feb 8, 2006)
**Bug fix: Sped up reminders lots. Added a caching mechanism for reminders that have already been matched.
* v2.3.4 (Feb 7, 2006)
**Bug fix: Cleaned up code to hopefully prevent the Firefox 1.5.0.1 crash that was causing lots of plugins
to crash Firefox. Thanks to http://www.jslint.com
* v2.3.3 (Feb 2, 2006)
**Feature: newReminder now has drop down lists instead of text boxes.
**Bug fix: A trailing space in a title would trigger an infinite loop.
**Bug fix: using tag:"birthday !reminder" would filter differently than tag:"!reminder birthday"
* v2.3.2 (Jan 21, 2006)
**Feature: newReminder macro, which will let you easily add a reminder to a tiddler. Thanks to Eric Shulman (http://www.elsdesign.com) for the code to do this.
** Bug fix: offsetday was not working sometimes
** Bug fix: when upgrading to 2.0, I included a bit to exclude tiddlers tagged with excludeSearch. I've reverted back to searching through all tiddlers
* v2.3.1 (Jan 7, 2006)
**Feature: 2.0 compatibility
**Feature AlanH sent some code to make sure that showReminders prints a message if no reminders are found.
* v2.3.0 (Jan 3, 2006)
** Bug Fix: Using "Last Sunday (-0)" as a offsetdayofweek wasn't working.
** Bug Fix: Daylight Savings time broke offset based reminders (for example year:2005 month:8 day:23 recurdays:7 would match Monday instead of Tuesday during DST.
!Code
***/
//{{{
//============================================================================
//============================================================================
// ReminderPlugin
//============================================================================
//============================================================================
version.extensions.ReminderPlugin = {major: 2, minor: 3, revision: 8, date: new Date(2006,3,9), source: "http://remindermacros.tiddlyspot.com/"};
//============================================================================
// Configuration
// Modify this section to change the defaults for
// leadtime and display strings
//============================================================================
config.macros.reminders = {};
config.macros["reminder"] = {};
config.macros["newReminder"] = {};
config.macros["showReminders"] = {};
config.macros["displayTiddlersWithReminders"] = {};
config.macros.reminders["defaultLeadTime"] = [0,6000];
config.macros.reminders["defaultReminderMessage"] = "DIFF: TITLE on DATE ANNIVERSARY";
config.macros.reminders["defaultShowReminderMessage"] = "DIFF: TITLE on DATE ANNIVERSARY -- TIDDLER";
config.macros.reminders["defaultAnniversaryMessage"] = "(DIFF)";
config.macros.reminders["untitledReminder"] = "Untitled Reminder";
config.macros.reminders["noReminderFound"] = "Couldn't find a match for TITLE in the next LEADTIMEUPPER days."
config.macros.reminders["todayString"] = "Today";
config.macros.reminders["tomorrowString"] = "Tomorrow";
config.macros.reminders["ndaysString"] = "DIFF days";
config.macros.reminders["emtpyShowRemindersString"] = "There are no upcoming events";
//============================================================================
// Code
// You should not need to edit anything
// below this. Make sure to edit this tiddler and copy
// the code from the text box, to make sure that
// tiddler rendering doesn't interfere with the copy
// and paste.
//============================================================================
//this object will hold the cache of reminders, so that we don't
//recompute the same reminder over again.
var reminderCache = {};
config.macros.showReminders.handler = function showReminders(place,macroName,params)
{
var now = new Date().getMidnight();
var paramHash = {};
var leadtime = [0,14];
paramHash = getParamsForReminder(params);
var bProvidedDate = (paramHash["year"] != null) ||
(paramHash["month"] != null) ||
(paramHash["day"] != null) ||
(paramHash["dayofweek"] != null);
if (paramHash["leadtime"] != null)
{
leadtime = paramHash["leadtime"];
if (bProvidedDate)
{
//If they've entered a day, we need to make
//sure to find it. We'll reset the
//leadtime a few lines down.
paramHash["leadtime"] = [-10000, 10000];
}
}
var matchedDate = now;
if (bProvidedDate)
{
var leadTimeLowerBound = new Date().getMidnight().addDays(paramHash["leadtime"][0]);
var leadTimeUpperBound = new Date().getMidnight().addDays(paramHash["leadtime"][1]);
matchedDate = findDateForReminder(paramHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound);
}
var arr = findTiddlersWithReminders(matchedDate, leadtime, paramHash["tag"], paramHash["limit"]);
var elem = createTiddlyElement(place,"span",null,null, null);
var mess = "";
if (arr.length == 0)
{
mess += config.macros.reminders.emtpyShowRemindersString;
}
for (var j = 0; j < arr.length; j++)
{
if (paramHash["format"] != null)
{
arr[j]["params"]["format"] = paramHash["format"];
}
else
{
arr[j]["params"]["format"] = config.macros.reminders["defaultShowReminderMessage"];
}
mess += getReminderMessageForDisplay(arr[j]["diff"], arr[j]["params"], arr[j]["matchedDate"], arr[j]["tiddler"]);
mess += "\n";
}
wikify(mess, elem, null, null);
};
config.macros.displayTiddlersWithReminders.handler = function displayTiddlersWithReminders(place,macroName,params)
{
var now = new Date().getMidnight();
var paramHash = {};
var leadtime = [0,14];
paramHash = getParamsForReminder(params);
var bProvidedDate = (paramHash["year"] != null) ||
(paramHash["month"] != null) ||
(paramHash["day"] != null) ||
(paramHash["dayofweek"] != null);
if (paramHash["leadtime"] != null)
{
leadtime = paramHash["leadtime"];
if (bProvidedDate)
{
//If they've entered a day, we need to make
//sure to find it. We'll reset the leadtime
//a few lines down.
paramHash["leadtime"] = [-10000,10000];
}
}
var matchedDate = now;
if (bProvidedDate)
{
var leadTimeLowerBound = new Date().getMidnight().addDays(paramHash["leadtime"][0]);
var leadTimeUpperBound = new Date().getMidnight().addDays(paramHash["leadtime"][1]);
matchedDate = findDateForReminder(paramHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound);
}
var arr = findTiddlersWithReminders(matchedDate, leadtime, paramHash["tag"], paramHash["limit"]);
for (var j = 0; j < arr.length; j++)
{
displayTiddler(null, arr[j]["tiddler"], 0, null, false, false, false);
}
};
config.macros.reminder.handler = function reminder(place,macroName,params)
{
var dateHash = getParamsForReminder(params);
if (dateHash["hidden"] != null)
{
return;
}
var leadTime = dateHash["leadtime"];
if (leadTime == null)
{
leadTime = config.macros.reminders["defaultLeadTime"];
}
var leadTimeLowerBound = new Date().getMidnight().addDays(leadTime[0]);
var leadTimeUpperBound = new Date().getMidnight().addDays(leadTime[1]);
var matchedDate = findDateForReminder(dateHash, new Date().getMidnight(), leadTimeLowerBound, leadTimeUpperBound);
if (!store.getTiddler)
{
store.getTiddler=function(title) {return this.tiddlers[title];};
}
var title = window.story.findContainingTiddler(place).id.substr(7);
if (matchedDate != null)
{
var diff = matchedDate.getDifferenceInDays(new Date().getMidnight());
var elem = createTiddlyElement(place,"span",null,null, null);
var mess = getReminderMessageForDisplay(diff, dateHash, matchedDate, title);
wikify(mess, elem, null, null);
}
else
{
createTiddlyElement(place,"span",null,null, config.macros.reminders["noReminderFound"].replace("TITLE", dateHash["title"]).replace("LEADTIMEUPPER", leadTime[1]).replace("LEADTIMELOWER", leadTime[0]).replace("TIDDLERNAME", title).replace("TIDDLER", "[[" + title + "]]") );
}
};
config.macros.newReminder.handler = function newReminder(place,macroName,params)
{
var today=new Date().getMidnight();
var formstring = '<html><form>Year: <select name="year"><option value="">Every year</option>';
for (var i = 0; i < 5; i++)
{
formstring += '<option' + ((i == 0) ? ' selected' : '') + ' value="' + (today.getFullYear() +i) + '">' + (today.getFullYear() + i) + '</option>';
}
formstring += '</select> Month:<select name="month"><option value="">Every month</option>';
for (i = 0; i < 12; i++)
{
formstring += '<option' + ((i == today.getMonth()) ? ' selected' : '') + ' value="' + (i+1) + '">' + config.messages.dates.months[i] + '</option>';
}
formstring += '</select> Day:<select name="day"><option value="">Every day</option>';
for (i = 1; i < 32; i++)
{
formstring += '<option' + ((i == (today.getDate() )) ? ' selected' : '') + ' value="' + i + '">' + i + '</option>';
}
formstring += '</select> Reminder Title:<input type="text" size="40" name="title" value="please enter a title" onfocus="this.select();"><input type="button" value="ok" onclick="addReminderToTiddler(this.form)"></form></html>';
var panel = config.macros.slider.createSlider(place,null,"New Reminder","Open a form to add a new reminder to this tiddler");
wikify(formstring ,panel,null,store.getTiddler(params[1]));
};
// onclick: process input and insert reminder at 'marker'
window.addReminderToTiddler = function(form) {
if (!store.getTiddler)
{
store.getTiddler=function(title) {return this.tiddlers[title];};
}
var title = window.story.findContainingTiddler(form).id.substr(7);
var tiddler=store.getTiddler(title);
var txt='\n<<reminder ';
if (form.year.value != "")
txt += 'year:'+form.year.value + ' ';
if (form.month.value != "")
txt += 'month:'+form.month.value + ' ';
if (form.day.value != "")
txt += 'day:'+form.day.value + ' ';
txt += 'title:"'+form.title.value+'" ';
txt +='>>';
tiddler.set(null,tiddler.text + txt);
window.story.refreshTiddler(title,1,true);
store.setDirty(true);
};
function hasTag(tiddlerTags, tagFilters)
{
//Make sure we respond well to empty tiddlerTaglists or tagFilterlists
if (tagFilters.length==0 || tiddlerTags.length==0)
{
return true;
}
var bHasTag = false;
/*bNoPos says: "'till now there has been no check using a positive filter"
Imagine a filterlist consisting of 1 negative filter:
If the filter isn't matched, we want hasTag to be true.
Yet bHasTag is still false ('cause only positive filters cause bHasTag to change)
If no positive filters are present bNoPos is true, and no negative filters are matched so we have not returned false
Thus: hasTag returns true.
If at any time a positive filter is encountered, we want at least one of the tags to match it, so we turn bNoPos to false, which
means bHasTag must be true for hasTag to return true*/
var bNoPos=true;
for (var t3 = 0; t3 < tagFilters.length; t3++)
{
for(var t2=0; t2<tiddlerTags.length; t2++)
{
if (tagFilters[t3].length > 1 && tagFilters[t3].charAt(0) == '!')
{
if (tiddlerTags[t2] == tagFilters[t3].substring(1))
{
//If at any time a negative filter is matched, we return false
return false;
}
}
else
{
if (bNoPos)
{
//We encountered the first positive filter
bNoPos=false;
}
if (tiddlerTags[t2] == tagFilters[t3])
{
//A positive filter is matched. As long as no negative filter is matched, hasTag will return true
bHasTag=true;
}
}
}
}
return (bNoPos || bHasTag);
};
//This function searches all tiddlers for the reminder //macro. It is intended that other plugins (like //calendar) will use this function to query for
//upcoming reminders.
//The arguments to this function filter out reminders //based on when they will fire.
//
//ARGUMENTS:
//baseDate is the date that is used as "now".
//leadtime is a two element int array, with leadtime[0]
// as the lower bound and leadtime[1] as the
// upper bound. A reasonable default is [0,14]
//tags is a space-separated list of tags to use to filter
// tiddlers. If a tag name begins with an !, then
// only tiddlers which do not have that tag will
// be considered. For example "examples holidays"
// will search for reminders in any tiddlers that
// are tagged with examples or holidays and
// "!examples !holidays" will search for reminders
// in any tiddlers that are not tagged with
// examples or holidays. Pass in null to search
// all tiddlers.
//limit. If limit is null, individual reminders can
// override the leadtime specified earlier.
// Pass in 1 in order to override that behavior.
window.findTiddlersWithReminders = function findTiddlersWithReminders(baseDate, leadtime, tags, limit)
{
//function(searchRegExp,sortField,excludeTag)
// var macroPattern = "<<([^>\\]+)(?:\\*)([^>]*)>>";
var macroPattern = "<<(reminder)(.*)>>";
var macroRegExp = new RegExp(macroPattern,"mg");
var matches = store.search(macroRegExp,"title","");
var arr = [];
var tagsArray = null;
if (tags != null)
{
// tagsArray = tags.split(" ");
tagsArray = tags.readBracketedList(); // allows tags with spaces. thanks Robin Summerhill, 4-Oct-06.
}
for(var t=matches.length-1; t>=0; t--)
{
if (tagsArray != null)
{
//If they specified tags to filter on, and this tiddler doesn't
//match, skip it entirely.
if ( ! hasTag(matches[t].tags, tagsArray))
{
continue;
}
}
var targetText = matches[t].text;
do {
// Get the next formatting match
var formatMatch = macroRegExp.exec(targetText);
if(formatMatch && formatMatch[1] != null && formatMatch[1].toLowerCase() == "reminder")
{
//Find the matching date.
var params = formatMatch[2] != null ? formatMatch[2].readMacroParams() : {};
var dateHash = getParamsForReminder(params);
if (limit != null || dateHash["leadtime"] == null)
{
if (leadtime == null)
dateHash["leadtime"] = leadtime;
else
{
dateHash["leadtime"] = [];
dateHash["leadtime"][0] = leadtime[0];
dateHash["leadtime"][1] = leadtime[1];
}
}
if (dateHash["leadtime"] == null)
dateHash["leadtime"] = config.macros.reminders["defaultLeadTime"];
var leadTimeLowerBound = baseDate.addDays(dateHash["leadtime"][0]);
var leadTimeUpperBound = baseDate.addDays(dateHash["leadtime"][1]);
var matchedDate = findDateForReminder(dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound);
while (matchedDate != null)
{
var hash = {};
hash["diff"] = matchedDate.getDifferenceInDays(baseDate);
hash["matchedDate"] = new Date(matchedDate.getFullYear(), matchedDate.getMonth(), matchedDate.getDate(), 0, 0);
hash["params"] = cloneParams(dateHash);
hash["tiddler"] = matches[t].title;
hash["tags"] = matches[t].tags;
arr.pushUnique(hash);
if (dateHash["recurdays"] != null || (dateHash["year"] == null))
{
leadTimeLowerBound = leadTimeLowerBound.addDays(matchedDate.getDifferenceInDays(leadTimeLowerBound)+ 1);
matchedDate = findDateForReminder(dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound);
}
else matchedDate = null;
}
}
}while(formatMatch);
}
if(arr.length > 1) //Sort the array by number of days remaining.
{
arr.sort(function (a,b) {if(a["diff"] == b["diff"]) {return(0);} else {return (a["diff"] < b["diff"]) ? -1 : +1; } });
}
return arr;
};
//This function takes the reminder macro parameters and
//generates the string that is used for display.
//This function is not intended to be called by
//other plugins.
window.getReminderMessageForDisplay= function getReminderMessageForDisplay(diff, params, matchedDate, tiddlerTitle)
{
var anniversaryString = "";
var reminderTitle = params["title"];
if (reminderTitle == null)
{
reminderTitle = config.macros.reminders["untitledReminder"];
}
if (params["firstyear"] != null)
{
anniversaryString = config.macros.reminders["defaultAnniversaryMessage"].replace("DIFF", (matchedDate.getFullYear() - params["firstyear"]));
}
var mess = "";
var diffString = "";
if (diff == 0)
{
diffString = config.macros.reminders["todayString"];
}
else if (diff == 1)
{
diffString = config.macros.reminders["tomorrowString"];
}
else
{
diffString = config.macros.reminders["ndaysString"].replace("DIFF", diff);
}
var format = config.macros.reminders["defaultReminderMessage"];
if (params["format"] != null)
{
format = params["format"];
}
mess = format;
//HACK! -- Avoid replacing DD in TIDDLER with the date
mess = mess.replace(/TIDDLER/g, "TIDELER");
mess = matchedDate.formatStringDateOnly(mess);
mess = mess.replace(/TIDELER/g, "TIDDLER");
if (tiddlerTitle != null)
{
mess = mess.replace(/TIDDLERNAME/g, tiddlerTitle);
mess = mess.replace(/TIDDLER/g, "[[" + tiddlerTitle + "]]");
}
mess = mess.replace("DIFF", diffString).replace("TITLE", reminderTitle).replace("DATE", matchedDate.formatString("DDD MMM DD, YYYY")).replace("ANNIVERSARY", anniversaryString);
return mess;
};
// Parse out the macro parameters into a hashtable. This
// handles the arguments for reminder, showReminders and
// displayTiddlersWithReminders.
window.getParamsForReminder = function getParamsForReminder(params)
{
var dateHash = {};
var type = "";
var num = 0;
var title = "";
for(var t=0; t<params.length; t++)
{
var split = params[t].split(":");
type = split[0].toLowerCase();
var value = split[1];
for (var i=2; i < split.length; i++)
{
value += ":" + split[i];
}
if (type == "nolinks" || type == "limit" || type == "hidden")
{
num = 1;
}
else if (type == "leadtime")
{
var leads = value.split("...");
if (leads.length == 1)
{
leads[1]= leads[0];
leads[0] = 0;
}
leads[0] = parseInt(leads[0], 10);
leads[1] = parseInt(leads[1], 10);
num = leads;
}
else if (type == "offsetdayofweek")
{
if (value.substr(0,1) == "-")
{
dateHash["negativeOffsetDayOfWeek"] = 1;
value = value.substr(1);
}
num = parseInt(value, 10);
}
else if (type != "title" && type != "tag" && type != "format")
{
num = parseInt(value, 10);
}
else
{
title = value;
t++;
while (title.substr(0,1) == '"' && title.substr(title.length - 1,1) != '"' && params[t] != undefined)
{
title += " " + params[t++];
}
//Trim off the leading and trailing quotes
if (title.substr(0,1) == "\"" && title.substr(title.length - 1,1)== "\"")
{
title = title.substr(1, title.length - 2);
t--;
}
num = title;
}
dateHash[type] = num;
}
//date is synonymous with day
if (dateHash["day"] == null)
{
dateHash["day"] = dateHash["date"];
}
return dateHash;
};
//This function finds the date specified in the reminder
//parameters. It will return null if no match can be
//found. This function is not intended to be used by
//other plugins.
window.findDateForReminder= function findDateForReminder( dateHash, baseDate, leadTimeLowerBound, leadTimeUpperBound)
{
if (baseDate == null)
{
baseDate = new Date().getMidnight();
}
var hashKey = baseDate.convertToYYYYMMDDHHMM();
for (var k in dateHash)
{
hashKey += "," + k + "|" + dateHash[k];
}
hashKey += "," + leadTimeLowerBound.convertToYYYYMMDDHHMM();
hashKey += "," + leadTimeUpperBound.convertToYYYYMMDDHHMM();
if (reminderCache[hashKey] == null)
{
//If we don't find a match in this run, then we will
//cache that the reminder can't be matched.
reminderCache[hashKey] = false;
}
else if (reminderCache[hashKey] == false)
{
//We've already tried this date and failed
return null;
}
else
{
return reminderCache[hashKey];
}
var bOffsetSpecified = dateHash["offsetyear"] != null ||
dateHash["offsetmonth"] != null ||
dateHash["offsetday"] != null ||
dateHash["offsetdayofweek"] != null ||
dateHash["recurdays"] != null;
// If we are matching the base date for a dayofweek offset, look for the base date a
//little further back.
var tmp1leadTimeLowerBound = leadTimeLowerBound;
if ( dateHash["offsetdayofweek"] != null)
{
tmp1leadTimeLowerBound = leadTimeLowerBound.addDays(-6);
}
var matchedDate = baseDate.findMatch(dateHash, tmp1leadTimeLowerBound, leadTimeUpperBound);
if (matchedDate != null)
{
var newMatchedDate = matchedDate;
if (dateHash["recurdays"] != null)
{
while (newMatchedDate.getTime() < leadTimeLowerBound.getTime())
{
newMatchedDate = newMatchedDate.addDays(dateHash["recurdays"]);
}
}
else if (dateHash["offsetyear"] != null ||
dateHash["offsetmonth"] != null ||
dateHash["offsetday"] != null ||
dateHash["offsetdayofweek"] != null)
{
var tmpdateHash = cloneParams(dateHash);
tmpdateHash["year"] = dateHash["offsetyear"];
tmpdateHash["month"] = dateHash["offsetmonth"];
tmpdateHash["day"] = dateHash["offsetday"];
tmpdateHash["dayofweek"] = dateHash["offsetdayofweek"];
var tmpleadTimeLowerBound = leadTimeLowerBound;
var tmpleadTimeUpperBound = leadTimeUpperBound;
if (tmpdateHash["offsetdayofweek"] != null)
{
if (tmpdateHash["negativeOffsetDayOfWeek"] == 1)
{
tmpleadTimeLowerBound = matchedDate.addDays(-6);
tmpleadTimeUpperBound = matchedDate;
}
else
{
tmpleadTimeLowerBound = matchedDate;
tmpleadTimeUpperBound = matchedDate.addDays(6);
}
}
newMatchedDate = matchedDate.findMatch(tmpdateHash, tmpleadTimeLowerBound, tmpleadTimeUpperBound);
//The offset couldn't be matched. return null.
if (newMatchedDate == null)
{
return null;
}
}
if (newMatchedDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
{
reminderCache[hashKey] = newMatchedDate;
return newMatchedDate;
}
}
return null;
};
//This does much the same job as findDateForReminder, but
//this one doesn't deal with offsets or recurring
//reminders.
Date.prototype.findMatch = function findMatch(dateHash, leadTimeLowerBound, leadTimeUpperBound)
{
var bSpecifiedYear = (dateHash["year"] != null);
var bSpecifiedMonth = (dateHash["month"] != null);
var bSpecifiedDay = (dateHash["day"] != null);
var bSpecifiedDayOfWeek = (dateHash["dayofweek"] != null);
if (bSpecifiedYear && bSpecifiedMonth && bSpecifiedDay)
{
return new Date(dateHash["year"], dateHash["month"]-1, dateHash["day"], 0, 0);
}
var bMatchedYear = !bSpecifiedYear;
var bMatchedMonth = !bSpecifiedMonth;
var bMatchedDay = !bSpecifiedDay;
var bMatchedDayOfWeek = !bSpecifiedDayOfWeek;
if (bSpecifiedDay && bSpecifiedMonth && !bSpecifiedYear && !bSpecifiedDayOfWeek)
{
//Shortcut -- First try this year. If it's too small, try next year.
var tmpMidnight = this.getMidnight();
var tmpDate = new Date(this.getFullYear(), dateHash["month"]-1, dateHash["day"], 0,0);
if (tmpDate.getTime() < leadTimeLowerBound.getTime())
{
tmpDate = new Date((this.getFullYear() + 1), dateHash["month"]-1, dateHash["day"], 0,0);
}
if ( tmpDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
{
return tmpDate;
}
else
{
return null;
}
}
var newDate = leadTimeLowerBound;
while (newDate.isBetween(leadTimeLowerBound, leadTimeUpperBound))
{
var tmp = testDate(newDate, dateHash, bSpecifiedYear, bSpecifiedMonth, bSpecifiedDay, bSpecifiedDayOfWeek);
if (tmp != null)
return tmp;
newDate = newDate.addDays(1);
}
};
function testDate(testMe, dateHash, bSpecifiedYear, bSpecifiedMonth, bSpecifiedDay, bSpecifiedDayOfWeek)
{
var bMatchedYear = !bSpecifiedYear;
var bMatchedMonth = !bSpecifiedMonth;
var bMatchedDay = !bSpecifiedDay;
var bMatchedDayOfWeek = !bSpecifiedDayOfWeek;
if (bSpecifiedYear)
{
bMatchedYear = (dateHash["year"] == testMe.getFullYear());
}
if (bSpecifiedMonth)
{
bMatchedMonth = ((dateHash["month"] - 1) == testMe.getMonth() );
}
if (bSpecifiedDay)
{
bMatchedDay = (dateHash["day"] == testMe.getDate());
}
if (bSpecifiedDayOfWeek)
{
bMatchedDayOfWeek = (dateHash["dayofweek"] == testMe.getDay());
}
if (bMatchedYear && bMatchedMonth && bMatchedDay && bMatchedDayOfWeek)
{
return testMe;
}
};
//Returns true if the date is in between two given dates
Date.prototype.isBetween = function isBetween(lowerBound, upperBound)
{
return (this.getTime() >= lowerBound.getTime() && this.getTime() <= upperBound.getTime());
}
//Return a new date, with the time set to midnight (0000)
Date.prototype.getMidnight = function getMidnight()
{
return new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0);
};
// Add the specified number of days to a date.
Date.prototype.addDays = function addDays(numberOfDays)
{
return new Date(this.getFullYear(), this.getMonth(), this.getDate() + numberOfDays, 0, 0);
};
//Return the number of days between two dates.
Date.prototype.getDifferenceInDays = function getDifferenceInDays(otherDate)
{
//I have to do it this way, because this way ignores daylight savings
var tmpDate = this.addDays(0);
if (this.getTime() > otherDate.getTime())
{
var i = 0;
for (i = 0; tmpDate.getTime() > otherDate.getTime(); i++)
{
tmpDate = tmpDate.addDays(-1);
}
return i;
}
else
{
var i = 0;
for (i = 0; tmpDate.getTime() < otherDate.getTime(); i++)
{
tmpDate = tmpDate.addDays(1);
}
return i * -1;
}
return 0;
};
function cloneParams(what) {
var tmp = {};
for (var i in what) {
tmp[i] = what[i];
}
return tmp;
}
// Substitute date components into a string
Date.prototype.formatStringDateOnly = function formatStringDateOnly(template)
{
template = template.replace("YYYY",this.getFullYear());
template = template.replace("YY",String.zeroPad(this.getFullYear()-2000,2));
template = template.replace("MMM",config.messages.dates.months[this.getMonth()]);
template = template.replace("0MM",String.zeroPad(this.getMonth()+1,2));
template = template.replace("MM",this.getMonth()+1);
template = template.replace("DDD",config.messages.dates.days[this.getDay()]);
template = template.replace("0DD",String.zeroPad(this.getDate(),2));
template = template.replace("DD",this.getDate());
return template;
};
//}}}
/***
|Name:|RenameTagsPlugin|
|Description:|Allows you to easily rename or delete tags across multiple tiddlers|
|Version:|3.0 ($Rev: 5501 $)|
|Date:|$Date: 2008-06-10 23:11:55 +1000 (Tue, 10 Jun 2008) $|
|Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {
prompts: {
rename: "Rename the tag '%0' to '%1' in %2 tidder%3?",
remove: "Remove the tag '%0' from %1 tidder%2?"
},
removeTag: function(tag,tiddlers) {
store.suspendNotifications();
for (var i=0;i<tiddlers.length;i++) {
store.setTiddlerTag(tiddlers[i].title,false,tag);
}
store.resumeNotifications();
store.notifyAll();
},
renameTag: function(oldTag,newTag,tiddlers) {
store.suspendNotifications();
for (var i=0;i<tiddlers.length;i++) {
store.setTiddlerTag(tiddlers[i].title,false,oldTag); // remove old
store.setTiddlerTag(tiddlers[i].title,true,newTag); // add new
}
store.resumeNotifications();
store.notifyAll();
},
storeMethods: {
saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,
saveTiddler: function(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created) {
if (title != newTitle) {
var tagged = this.getTaggedTiddlers(title);
if (tagged.length > 0) {
// then we are renaming a tag
if (confirm(config.renameTags.prompts.rename.format([title,newTitle,tagged.length,tagged.length>1?"s":""])))
config.renameTags.renameTag(title,newTitle,tagged);
if (!this.tiddlerExists(title) && newBody == "")
// dont create unwanted tiddler
return null;
}
}
return this.saveTiddler_orig_renameTags(title,newTitle,newBody,modifier,modified,tags,fields,clearChangeCount,created);
},
removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,
removeTiddler: function(title) {
var tagged = this.getTaggedTiddlers(title);
if (tagged.length > 0)
if (confirm(config.renameTags.prompts.remove.format([title,tagged.length,tagged.length>1?"s":""])))
config.renameTags.removeTag(title,tagged);
return this.removeTiddler_orig_renameTags(title);
}
},
init: function() {
merge(TiddlyWiki.prototype,this.storeMethods);
}
}
config.renameTags.init();
//}}}
/***
|Name:|SaveCloseTiddlerPlugin|
|Description:|Provides two extra toolbar commands, saveCloseTiddler and cancelCloseTiddler|
|Version:|3.0 ($Rev: 5502 $)|
|Date:|$Date: 2008-06-10 23:31:39 +1000 (Tue, 10 Jun 2008) $|
|Source:|http://mptw.tiddlyspot.com/#SaveCloseTiddlerPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
To use these you must add them to the tool bar in your EditTemplate
***/
//{{{
merge(config.commands,{
saveCloseTiddler: {
text: 'done/close',
tooltip: 'Save changes to this tiddler and close it',
handler: function(ev,src,title) {
var closeTitle = title;
var newTitle = story.saveTiddler(title,ev.shiftKey);
if (newTitle)
closeTitle = newTitle;
return config.commands.closeTiddler.handler(ev,src,closeTitle);
}
},
cancelCloseTiddler: {
text: 'cancel/close',
tooltip: 'Undo changes to this tiddler and close it',
handler: function(ev,src,title) {
// the same as closeTiddler now actually
return config.commands.closeTiddler.handler(ev,src,title);
}
}
});
//}}}
/***
|Name:|SelectThemePlugin|
|Description:|Lets you easily switch theme and palette|
|Version:|1.0.1 ($Rev: 3646 $)|
|Date:|$Date: 2008-02-27 02:34:38 +1000 (Wed, 27 Feb 2008) $|
|Source:|http://mptw.tiddlyspot.com/#SelectThemePlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
* Borrows largely from ThemeSwitcherPlugin by Martin Budden http://www.martinswiki.com/#ThemeSwitcherPlugin
* Theme is cookie based. But set a default by setting config.options.txtTheme in MptwConfigPlugin (for example)
* Palette is not cookie based. It actually overwrites your ColorPalette tiddler when you select a palette, so beware.
!Usage
* {{{<<selectTheme>>}}} makes a dropdown selector
* {{{<<selectPalette>>}}} makes a dropdown selector
* {{{<<applyTheme>>}}} applies the current tiddler as a theme
* {{{<<applyPalette>>}}} applies the current tiddler as a palette
* {{{<<applyTheme TiddlerName>>}}} applies TiddlerName as a theme
* {{{<<applyPalette TiddlerName>>}}} applies TiddlerName as a palette
***/
//{{{
config.macros.selectTheme = {
label: {
selectTheme:"select theme",
selectPalette:"select palette"
},
prompt: {
selectTheme:"Select the current theme",
selectPalette:"Select the current palette"
},
tags: {
selectTheme:'systemTheme',
selectPalette:'systemPalette'
}
};
config.macros.selectTheme.handler = function(place,macroName)
{
var btn = createTiddlyButton(place,this.label[macroName],this.prompt[macroName],this.onClick);
// want to handle palettes and themes with same code. use mode attribute to distinguish
btn.setAttribute('mode',macroName);
};
config.macros.selectTheme.onClick = function(ev)
{
var e = ev ? ev : window.event;
var popup = Popup.create(this);
var mode = this.getAttribute('mode');
var tiddlers = store.getTaggedTiddlers(config.macros.selectTheme.tags[mode]);
// for default
if (mode == "selectPalette") {
var btn = createTiddlyButton(createTiddlyElement(popup,'li'),"(default)","default color palette",config.macros.selectTheme.onClickTheme);
btn.setAttribute('theme',"(default)");
btn.setAttribute('mode',mode);
}
for(var i=0; i<tiddlers.length; i++) {
var t = tiddlers[i].title;
var name = store.getTiddlerSlice(t,'Name');
var desc = store.getTiddlerSlice(t,'Description');
var btn = createTiddlyButton(createTiddlyElement(popup,'li'), name?name:t, desc?desc:config.macros.selectTheme.label['mode'], config.macros.selectTheme.onClickTheme);
btn.setAttribute('theme',t);
btn.setAttribute('mode',mode);
}
Popup.show();
return stopEvent(e);
};
config.macros.selectTheme.onClickTheme = function(ev)
{
var mode = this.getAttribute('mode');
var theme = this.getAttribute('theme');
if (mode == 'selectTheme')
story.switchTheme(theme);
else // selectPalette
config.macros.selectTheme.updatePalette(theme);
return false;
};
config.macros.selectTheme.updatePalette = function(title)
{
if (title != "") {
store.deleteTiddler("ColorPalette");
if (title != "(default)")
store.saveTiddler("ColorPalette","ColorPalette",store.getTiddlerText(title),
config.options.txtUserName,undefined,"");
refreshAll();
if(config.options.chkAutoSave)
saveChanges(true);
}
};
config.macros.applyTheme = {
label: "apply",
prompt: "apply this theme or palette" // i'm lazy
};
config.macros.applyTheme.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
var useTiddler = params[0] ? params[0] : tiddler.title;
var btn = createTiddlyButton(place,this.label,this.prompt,config.macros.selectTheme.onClickTheme);
btn.setAttribute('theme',useTiddler);
btn.setAttribute('mode',macroName=="applyTheme"?"selectTheme":"selectPalette"); // a bit untidy here
}
config.macros.selectPalette = config.macros.selectTheme;
config.macros.applyPalette = config.macros.applyTheme;
config.macros.refreshAll = { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
createTiddlyButton(place,"refresh","refresh layout and styles",function() { refreshAll(); });
}};
//}}}
/%
!info
|Name|ShowPopup|
|Source|http://www.TiddlyTools.com/#ShowPopup|
|Version|1.1.0|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|transcluded html|
|Requires||
|Overrides||
|Description|display tiddler content in a TiddlyWiki popup panel|
Usage:
<<<
{{{
<<tiddler ShowPopup with: TiddlerName label tooltip buttonClass width popupClass>>
}}}
*{{{TiddlerName}}} is the title of the tiddler whose content is to be displayed
*{{{label}}} is the text of the popup command
*{{{tooltip}}} is the mouseover help text for the command
*{{{buttonClass}}} is a CSS classname applied to the command text (default=button)
*{{{width}}} is the width of the popup (using CSS measurements, default=auto)
*{{{popupClass}}} is a CSS classname applied to the popup panel (default=none). Use 'sticky' for persistent popups (requires StickyPopupPlugin)
<<<
Example:
<<<
{{{
<<tiddler ShowPopup with: ShowPopup [[Try this]] [[show this tiddler in a popup]]>>
}}}
<<tiddler ShowPopup with: ShowPopup [[Try this]] [[show this tiddler in a popup]]>>
<<<
!end
!show
<html><hide linebreaks>
<a href="javascript:;" class="$4" title="$3" onclick="
var p=Popup.create(this);if(!p)return;p.className+=' $6';var t=store.getTiddlerText('$1','');
var d=createTiddlyElement(p,'div');var s=d.style;s.whiteSpace='normal';s.width='$5';s.padding='2px';wikify(t,d);
Popup.show();event.cancelBubble=true;if(event.stopPropagation)event.stopPropagation();return(false);
">$2</a></html>
!end
%/<<tiddler {{'ShowPopup##'+('$1'=='$'+'1'?'info':'show')}} with: [[$1]] [[$2]] [[$3]] [[$4]] [[$5]] [[$6]]>>
{{here is a test tiddler for showpopup}}}
x
y
z
a
b
c
/***
|''Name''|SimpleSearchPlugin|
|''Description''|displays search results as a simple list of matching tiddlers|
|''Authors''|FND|
|''Version''|0.4.0|
|''Status''|stable|
|''Source''|http://devpad.tiddlyspot.com/#SimpleSearchPlugin|
|''CodeRepository''|http://svn.tiddlywiki.org/Trunk/contributors/FND/plugins/SimpleSearchPlugin.js|
|''License''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''Keywords''|search|
!Revision History
!!v0.2.0 (2008-08-18)
* initial release
!!v0.3.0 (2008-08-19)
* added Open All button (renders Classic Search option obsolete)
* sorting by relevance (title matches before content matches)
!!v0.4.0 (2008-08-26)
* added tag matching
!To Do
* tag matching optional
* animations for container creation and removal
* when clicking on search results, do not scroll to the respective tiddler (optional)
* use template for search results
!Code
***/
//{{{
if(!version.extensions.SimpleSearchPlugin) { //# ensure that the plugin is only installed once
version.extensions.SimpleSearchPlugin = { installed: true };
if(!plugins) { var plugins = {}; }
plugins.SimpleSearchPlugin = {
heading: "Search Results",
containerId: "searchResults",
btnCloseLabel: "close",
btnCloseTooltip: "dismiss search results",
btnCloseId: "search_close",
btnOpenLabel: "Open all",
btnOpenTooltip: "open all search results",
btnOpenId: "search_open",
displayResults: function(matches, query) {
story.refreshAllTiddlers(true); // update highlighting within story tiddlers
var el = document.getElementById(this.containerId);
query = '"""' + query + '"""'; // prevent WikiLinks
if(el) {
removeChildren(el);
} else { //# fallback: use displayArea as parent
var container = document.getElementById("displayArea");
el = document.createElement("div");
el.setAttribute("id", this.containerId);
el = container.insertBefore(el, container.firstChild);
}
var msg = "!" + this.heading + "\n";
if(matches.length > 0) {
msg += "''" + config.macros.search.successMsg.format([matches.length.toString(), query]) + ":''\n";
this.results = [];
for(var i = 0 ; i < matches.length; i++) {
this.results.push(matches[i].title);
msg += "* [[" + matches[i].title + "]]\n";
}
} else {
msg += "''" + config.macros.search.failureMsg.format([query]) + "''"; // XXX: do not use bold here!?
}
createTiddlyButton(el, this.btnCloseLabel, this.btnCloseTooltip, plugins.SimpleSearchPlugin.closeResults, "button", this.btnCloseId);
wikify(msg, el);
if(matches.length > 0) { // XXX: redundant!?
createTiddlyButton(el, this.btnOpenLabel, this.btnOpenTooltip, plugins.SimpleSearchPlugin.openAll, "button", this.btnOpenId);
}
},
closeResults: function() {
var el = document.getElementById(plugins.SimpleSearchPlugin.containerId);
removeNode(el);
plugins.SimpleSearchPlugin.results = null;
highlightHack = null;
},
openAll: function(ev) {
story.displayTiddlers(null, plugins.SimpleSearchPlugin.results);
return false;
}
};
config.shadowTiddlers.StyleSheetSimpleSearch = "/*{{{*/\n" +
"#" + plugins.SimpleSearchPlugin.containerId + " {\n" +
"\toverflow: auto;\n" +
"\tpadding: 5px 1em 10px;\n" +
"\tbackground-color: [[ColorPalette::TertiaryPale]];\n" +
"}\n\n" +
"#" + plugins.SimpleSearchPlugin.containerId + " h1 {\n" +
"\tmargin-top: 0;\n" +
"\tborder: none;\n" +
"}\n\n" +
"#" + plugins.SimpleSearchPlugin.containerId + " ul {\n" +
"\tmargin: 0.5em;\n" +
"\tpadding-left: 1.5em;\n" +
"}\n\n" +
"#" + plugins.SimpleSearchPlugin.containerId + " .button {\n" +
"\tdisplay: block;\n" +
"\tborder-color: [[ColorPalette::TertiaryDark]];\n" +
"\tpadding: 5px;\n" +
"\tbackground-color: [[ColorPalette::TertiaryLight]];\n" +
"}\n\n" +
"#" + plugins.SimpleSearchPlugin.containerId + " .button:hover {\n" +
"\tborder-color: [[ColorPalette::SecondaryMid]];\n" +
"\tbackground-color: [[ColorPalette::SecondaryLight]];\n" +
"}\n\n" +
"#" + plugins.SimpleSearchPlugin.btnCloseId + " {\n" +
"\tfloat: right;\n" +
"\tmargin: -5px -1em 5px 5px;\n" +
"}\n\n" +
"#" + plugins.SimpleSearchPlugin.btnOpenId + " {\n" +
"\tfloat: left;\n" +
"\tmargin-top: 5px;\n" +
"}\n" +
"/*}}}*/";
store.addNotification("StyleSheetSimpleSearch", refreshStyles);
// override Story.search()
Story.prototype.search = function(text, useCaseSensitive, useRegExp) {
highlightHack = new RegExp(useRegExp ? text : text.escapeRegExp(), useCaseSensitive ? "mg" : "img");
var matches = store.search(highlightHack, null, "excludeSearch");
var q = useRegExp ? "/" : "'";
plugins.SimpleSearchPlugin.displayResults(matches, q + text + q);
};
// override TiddlyWiki.search() to sort by relevance
TiddlyWiki.prototype.search = function(searchRegExp, sortField, excludeTag, match) {
var candidates = this.reverseLookup("tags", excludeTag, !!match);
var primary = [];
var secondary = [];
var tertiary = [];
for(var t = 0; t < candidates.length; t++) {
if(candidates[t].title.search(searchRegExp) != -1) {
primary.push(candidates[t]);
} else if(candidates[t].tags.join(" ").search(searchRegExp) != -1) {
secondary.push(candidates[t]);
} else if(candidates[t].text.search(searchRegExp) != -1) {
tertiary.push(candidates[t]);
}
}
var results = primary.concat(secondary).concat(tertiary);
if(sortField) {
results.sort(function(a, b) {
return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);
});
}
return results;
};
} //# end of "install only once"
//}}}
.emphasis { color: black; font-weight: bold; border-bottom: 1px solid green; }
.hint { color: black; background: lightgray; visibility: visible;
font-style: italic; font-weight: bold;
padding-left: 5px; padding-right: 5px; }
.intro { color: black; font: 11pt arial, hevetica, sans-serif; font-style: italic; font-weight: bold; }
.kihap { color: brown;
font-style: italic; font-weight: bold; border-bottom: 2px solid red; }
/* use green and red colors to highlight left and right directions */
.left { color: red; font-size:12pt; font-variant: small-caps; font-weight: bold; }
.right { color: seagreen; font-size: 12pt; font-variant: small-caps; font-weight: bold; }
{{intro{Custom tags created by sww}}}
* [[sww]]: added by me
* [[log]]: logged events / notes
* [[ref]]: reference information
* [[todo]]: things to be done
* [[done]]: things that have been completed
^^[img[favicon.ico]] TiddlyWiki <<version>> MPTW <<mptwVersion>>
![[Tweaks Completed]]
!!! Misc:
* Used <<selectTheme>> and <<selectPalette>> to customize appearance
* Added "go to top of page" button to bottom of page by adding the following code to the bottom of the PageTemplate
{{{
<div style="position:fixed;z-index:1001;bottom:.1em;right:.1em;cursor:pointer;font-size:9pt;">
<a href="javascript:window.scrollTo(0,0)" title="scroll to top of page">▲</a>
</div>
}}}
* Added the ContentsSlider to PageTemplate by changing {{{<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>}}} to {{{<div id='sidebarTabs' refresh='content' force='true' tiddler='ContentsSlider'></div>}}}
* Added the content header to the PageTemplate for the MptwTheme's displayArea: {{{<div class='tiddler' id='hD' refresh='content' tiddler='contentHeader'></div>}}}; purpose is to permantently display a QOTD at the top
* Added StyleSheet
!!! Added:
* ImportTiddlersPlugin: <<importTiddlers inline>>
* CalendarPlugin: DatePlugin, ReminderMacros <<calendar 2009 7>> <<showReminders leadtime:30>>
* ShowPopup: <<tiddler ShowPopup with: ShowPopupTest label tooltip>>
* ToggleRightSidebar (and InlineJavascriptPlugin): show/hide the right sidebar
* SimpleSearchPlugin: show search results within a single box
* QuoteOfTheDayPlugin: display a quote at random
* ImagePopupPlugin (and NestedSlidersPlugin): toggle image between thumbnail and larger size; see ImageFunctionsTest and ImagePopupTestImage for example
* SystemInfoPlugin: summarize system info <<systemInfo>>;
* ContentsSlider: show/hide list of tiddlers (works only with some MPTW themes)
* MemorizablePlugin: practice memorizing tiddler content arranged in a two column table;
* CleanupContentPlugin: apply consistent naming/formatting to tiddler contents eg <<cleanupContentPlugin "Jah Won" >>
* TiddlerTweakerPlugin: edit various tiddler attributes/fields
* ImageSizePlugin: resize images
![[Tweaks Desired]]
* in top menu, move the search box and the togglerightsidebar to the right margin
/***
|Name|SystemInfoPlugin|
|Source|http://www.TiddlyTools.com/#SystemInfoPlugin|
|Version|1.7.1|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|view system internal data and settings|
~TidIDE (//prounounced "Tie Dyed"//) - ''Tid''dlyWiki ''I''ntegrated ''D''evelopment ''E''nvironment - tools for ~TiddlyWiki authors and editors.
You can use the {{{<<systemInfo>>}}} control panel to view a variety of system internal data and functions, and view/modify ''all'' of ~TiddlyWiki's internal config.option.* settings. NOTE: Non-default config.options are stored in cookies and are retrieved whenever the TW document is loaded into a browser; however, ''core TW functions and custom-defined plugins can explicitly ignore or reset any locally-stored cookie values and use their own, internally-defined values'' instead. As a result, changes to these may be completely ignored, or may only have an effect during the current TW document "session" (i.e., until the TW document is reloaded), even though a persistent cookie value has been saved.
!!!!!Usage/Example
<<<
{{{<<systemInfo>>}}}
{{smallform{<<systemInfo>>}}}
<<<
!!!!!Revisions
<<<
''2007.10.31 [1.7.1]'' code reduction: when filling globals droplist, instead of using a large, static "global exclusion list", simply skip global *functions*, while still listing all other global properties, including key TW internal objects such as "config".
''2007.09.09 [1.7.0]'' split from TidIDEPlugin
|please see [[TidIDEPluginInfo]] for additional revision details|
''2006.04.15 [0.5.0]'' Initial ALPHA release. Converted from inline script.
<<<
!!!!!Code
***/
//{{{
version.extensions.SystemInfoPlugin= {major: 1, minor: 7, revision: 1, date: new Date(2006,10,31)};
config.shadowTiddlers.SystemInfo="<<systemInfo>>";
config.macros.systemInfo = {
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var span=createTiddlyElement(place,"span")
span.innerHTML=this.html;
this.getsys(span.getElementsByTagName("form")[0]); // initialize form
},
getsys: function(f) {
f.sysview.value="";
// OPTIONS
while (f.sys_opts.options.length > 1) { f.sys_opts.options[1]=null; } // clear list
f.config_view.value=""; // clear edit field
var cookies = { };
if (document.cookie != "") {
var p = document.cookie.split("; ");
for (var i=0; i < p.length; i++) {
var pos=p[i].indexOf("=");
if (pos==-1)
cookies[p[i]]="";
else
cookies[p[i].substr(0,pos)]=unescape(p[i].slice(pos+1));
}
}
var c=1;
var opt=new Array(); for (var i in config.options) opt.push(i); opt.sort();
for(var i=0; i<opt.length; i++) {
if ((opt[i].substr(0,3)=="txt")||(opt[i].substr(0,3)=="chk")) {
var txt = (opt[i].substr(0,3)=="chk"?("["+(config.options[opt[i]]?"x":"_")+"] "):"")+opt[i]+(cookies[opt[i]]?" (cookie)":"");
var val = config.options[opt[i]];
f.sys_opts.options[c++]=new Option(txt,val,false,false);
}
}
// STYLESHEETS
while (f.sys_styles.options.length > 1) { f.sys_styles.options[1]=null; } // clear list
var c=1;
var styles=document.getElementsByTagName("style");
for(var i=0; i < styles.length; i++) {
var id=styles[i].getAttribute("id"); if (!id) id="(default)";
var txt=id;
var val="/* stylesheet:"+txt+" */\n"+styles[i].innerHTML;
f.sys_styles.options[c++]=new Option(txt,val,false,false);
}
// SHADOWS
while (f.sys_shadows.options.length > 1) { f.sys_shadows.options[1]=null; } // clear list
var c=1;
for(var s in config.shadowTiddlers) f.sys_shadows.options[c++]=new Option(s,config.shadowTiddlers[s],false,false);
// NOTIFICATIONS
while (f.sys_notify.options.length > 1) { f.sys_notify.options[1]=null; } // clear list
var c=1;
for (var i=0; i<store.namedNotifications.length; i++) {
var n = store.namedNotifications[i];
var fn = n.notify.toString();
fn = fn.substring(fn.indexOf("function ")+9,fn.indexOf("{")-1);
var txt=(n.name?n.name:"any change")+"="+fn;
var val="/* notify: "+txt+" */\n"+n.notify.toString();
f.sys_notify.options[c++]=new Option(txt,val,false,false);
}
// MACROS
while (f.sys_macros.options.length > 1) { f.sys_macros.options[1]=null; } // clear list
var c=1;
var macros=new Array(); for (var m in config.macros) macros.push(m); macros.sort();
for(var i=0; i < macros.length; i++)
f.sys_macros.options[c++]=new Option(macros[i],this.showObject(config.macros[macros[i]]),false,false);
// COMMANDS
while (f.sys_commands.options.length > 1) { f.sys_commands.options[1]=null; } // clear list
var c=1;
for(var cmd in config.commands)
f.sys_commands.options[c++]=new Option(cmd,this.showObject(config.commands[cmd]),false,false);
// FORMATTERS
while (f.sys_formatters.options.length > 1) { f.sys_formatters.options[1]=null; } // clear list
var c=1;
for(var i=0; i < config.formatters.length; i++)
f.sys_formatters.options[c++]=new Option(config.formatters[i].name,this.showObject(config.formatters[i]),false,false);
// PARAMIFIERS
while (f.sys_params.options.length > 1) { f.sys_params.options[1]=null; } // clear list
var c=1;
for(var param in config.paramifiers)
f.sys_params.options[c++]=new Option(param,this.showObject(config.paramifiers[param]),false,false);
// GLOBALS
//global variables and functions (excluding most DOM and ~TiddyWiki core definitions)://
while (f.sys_globals.options.length > 1) { f.sys_globals.options[1]=null; } // clear list
if (config.browser.isIE) return; // BYPASS - 8/16/2006 // DON'T LIST GLOBALS IN IE... throws object error - WFFL
try {
var c=1;
for (var v in window) if ((typeof window[v])!='function') {
var t=window[v];
if ((typeof window[v])=='object') {
var t='';
for (var p in window[v]) {
t+=((typeof window[v][p])!='function')?('['+typeof window[v][p]+'] '+p):p;
t+=((typeof window[v][p])!='function')?('='+window[v][p]):'';
t+='\n';
}
}
f.sys_globals.options[c++]=new Option(((typeof window[v])!='function')?('['+typeof window[v]+'] '+v):v,t,false,false);
}
}
catch(e) { ; }
},
setsys: function(f) {
if (f.sys_opts.selectedIndex==0) return; // heading - do nothing
var name=f.sys_opts.options[f.sys_opts.selectedIndex].text.replace(/\[[Xx_]\] /,'').replace(/ \(cookie\)/,'')
var value=f.config_view.value;
config.options[name]=value;
saveOptionCookie(name);
f.sys_opts.options[f.sys_opts.selectedIndex].value=value;
return;
},
showObject: function(o) { // generate formatted output for displaying object references
var t="";
for (var p in o) {
if (typeof o[p]=="function") {
t+="- - - - - - - - - - "+p+" - - - - - - - - - -\n";
t+=o[p].toString();
t+="\n- - - - - - - - - - END: "+p+" - - - - - - - - - -\n";
}
else
t+='['+typeof o[p]+'] '+p+": "+o[p]+"\n";
}
return t;
},
html: "\
<form style='display:inline;margin:0;padding:0;'> \
<!-- configurable options --> \
<table style='width:100%;border:0;padding:0;margin:0'><tr style='border:0;padding:0;margin:0'> \
<td style='width:30%;border:0;padding:0;margin:0'> \
<select size=1 name='sys_opts' style='width:100%;' \
onchange='this.form.config_view.value=this.value'> \
<option value=\"\">config.options.*</option> \
</select> \
</td><td style='width:50%;border:0;padding:0;margin:0;'> \
<input type=text name='config_view' size=60 style='width:99%;' value=''> \
</td><td style='width:20%;white-space:nowrap;border:0;padding:0;margin:0;'> \
<input type=button style='width:50%;' value='set option' title='save this TiddlyWiki option value' \
onclick='config.macros.systemInfo.setsys(this.form);config.macros.systemInfo.getsys(this.form);'><!-- \
--><input type=button style='width:50%;' value='refresh' title='retrieve current options and system values' \
onclick='this.form.sysview.style.display=\"none\"; config.macros.systemInfo.getsys(this.form);'> \
</td></tr><tr style='border:0;padding:0;margin:0'><td colspan=3 \
style='white-space:nowrap;width:100%;border:0;padding:0;margin:0'> \
<!-- system objects --> \
<select size=1 name='sys_styles' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">stylesheets...</option> \
</select><select size=1 name='sys_shadows' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">shadows...</option> \
</select><select size=1 name='sys_notify' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">notifications...</option> \
</select><select size=1 name='sys_globals' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">globals...</option> \
</select><br><select size=1 name='sys_macros' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">macros...</option> \
</select><select size=1 name='sys_commands' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">commands...</option> \
</select><select size=1 name='sys_formatters' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">formatters...</option> \
</select><select size=1 name='sys_params' style='width:25%;' \
onchange='this.form.sysview.style.display=\"block\"; this.form.sysview.value=this.value'> \
<option value=\"\">paramifiers...</option> \
</select> \
<!-- system value display area --> \
<span style='white-space:normal;'><textarea id='sysview' name=sysview cols=60 rows=12 \
onfocus='this.select()' style='width:99.5%;height:16em;display:none'></textarea></span> \
</td></tr></table> \
</form>"
}
//}}}
<<tabs txtMoreTab "Tags" "All Tags" TabAllTags "Miss" "Missing tiddlers" TabMoreMissing "Orph" "Orphaned tiddlers" TabMoreOrphans "Shad" "Shadowed tiddlers" TabMoreShadowed>>
<<allTags excludeLists [a-z]>>
/***
|Name:|TagglyTaggingPlugin|
|Description:|tagglyTagging macro is a replacement for the builtin tagging macro in your ViewTemplate|
|Version:|3.3.1 ($Rev: 9828 $)|
|Date:|$Date: 2009-06-03 21:38:41 +1000 (Wed, 03 Jun 2009) $|
|Source:|http://mptw.tiddlyspot.com/#TagglyTaggingPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
See http://mptw.tiddlyspot.com/#TagglyTagging
***/
//{{{
merge(String.prototype,{
parseTagExpr: function(debug) {
if (this.trim() == "")
return "(true)";
var anyLogicOp = /(!|&&|\|\||\(|\))/g;
var singleLogicOp = /^(!|&&|\|\||\(|\))$/;
var spaced = this.
// because square brackets in templates are no good
// this means you can use [(With Spaces)] instead of [[With Spaces]]
replace(/\[\(/g," [[").
replace(/\)\]/g,"]] ").
// space things out so we can use readBracketedList. tricky eh?
replace(anyLogicOp," $1 ");
var expr = "";
var tokens = spaced.readBracketedList(false); // false means don't uniq the list. nice one JR!
for (var i=0;i<tokens.length;i++)
if (tokens[i].match(singleLogicOp))
expr += tokens[i];
else
expr += "tiddler.tags.contains('%0')".format([tokens[i].replace(/'/,"\\'")]); // fix single quote bug. still have round bracket bug i think
if (debug)
alert(expr);
return '('+expr+')';
}
});
merge(TiddlyWiki.prototype,{
getTiddlersByTagExpr: function(tagExpr,sortField) {
var result = [];
var expr = tagExpr.parseTagExpr();
store.forEachTiddler(function(title,tiddler) {
if (eval(expr))
result.push(tiddler);
});
if(!sortField)
sortField = "title";
result.sort(function(a,b) {return a[sortField] < b[sortField] ? -1 : (a[sortField] == b[sortField] ? 0 : +1);});
return result;
}
});
config.taggly = {
// for translations
lingo: {
labels: {
asc: "\u2191", // down arrow
desc: "\u2193", // up arrow
title: "title",
modified: "modified",
created: "created",
show: "+",
hide: "-",
normal: "normal",
group: "group",
commas: "commas",
sitemap: "sitemap",
numCols: "cols\u00b1", // plus minus sign
label: "Tagged as '%0':",
exprLabel: "Matching tag expression '%0':",
excerpts: "excerpts",
descr: "descr",
slices: "slices",
contents: "contents",
sliders: "sliders",
noexcerpts: "title only",
noneFound: "(none)"
},
tooltips: {
title: "Click to sort by title",
modified: "Click to sort by modified date",
created: "Click to sort by created date",
show: "Click to show tagging list",
hide: "Click to hide tagging list",
normal: "Click to show a normal ungrouped list",
group: "Click to show list grouped by tag",
sitemap: "Click to show a sitemap style list",
commas: "Click to show a comma separated list",
numCols: "Click to change number of columns",
excerpts: "Click to show excerpts",
descr: "Click to show the description slice",
slices: "Click to show all slices",
contents: "Click to show entire tiddler contents",
sliders: "Click to show tiddler contents in sliders",
noexcerpts: "Click to show entire title only"
},
tooDeepMessage: "* //sitemap too deep...//"
},
config: {
showTaggingCounts: true,
listOpts: {
// the first one will be the default
sortBy: ["title","modified","created"],
sortOrder: ["asc","desc"],
hideState: ["show","hide"],
listMode: ["normal","group","sitemap","commas"],
numCols: ["1","2","3","4","5","6"],
excerpts: ["noexcerpts","excerpts","descr","slices","contents","sliders"]
},
valuePrefix: "taggly.",
excludeTags: ["excludeLists","excludeTagging"],
excerptSize: 50,
excerptMarker: "/%"+"%/",
siteMapDepthLimit: 25
},
getTagglyOpt: function(title,opt) {
var val = store.getValue(title,this.config.valuePrefix+opt);
return val ? val : this.config.listOpts[opt][0];
},
setTagglyOpt: function(title,opt,value) {
// create it silently if it doesn't exist
if (!store.tiddlerExists(title)) {
store.saveTiddler(title,title,config.views.editor.defaultText.format([title]),config.options.txtUserName,new Date(),"");
// <<tagglyTagging expr:"...">> creates a tiddler to store its display settings
// Make those tiddlers less noticeable by tagging as excludeSearch and excludeLists
// Because we don't want to hide real tags, check that they aren't actually tags before doing so
// Also tag them as tagglyExpression for manageability
// (contributed by RA)
if (!store.getTaggedTiddlers(title).length) {
store.setTiddlerTag(title,true,"excludeSearch");
store.setTiddlerTag(title,true,"excludeLists");
store.setTiddlerTag(title,true,"tagglyExpression");
}
}
// if value is default then remove it to save space
return store.setValue(title, this.config.valuePrefix+opt, value == this.config.listOpts[opt][0] ? null : value);
},
getNextValue: function(title,opt) {
var current = this.getTagglyOpt(title,opt);
var pos = this.config.listOpts[opt].indexOf(current);
// supposed to automagically don't let cols cycle up past the number of items
// currently broken in some situations, eg when using an expression
// lets fix it later when we rewrite for jquery
// the columns thing should be jquery table manipulation probably
var limit = (opt == "numCols" ? store.getTaggedTiddlers(title).length : this.config.listOpts[opt].length);
var newPos = (pos + 1) % limit;
return this.config.listOpts[opt][newPos];
},
toggleTagglyOpt: function(title,opt) {
var newVal = this.getNextValue(title,opt);
this.setTagglyOpt(title,opt,newVal);
},
createListControl: function(place,title,type) {
var lingo = config.taggly.lingo;
var label;
var tooltip;
var onclick;
if ((type == "title" || type == "modified" || type == "created")) {
// "special" controls. a little tricky. derived from sortOrder and sortBy
label = lingo.labels[type];
tooltip = lingo.tooltips[type];
if (this.getTagglyOpt(title,"sortBy") == type) {
label += lingo.labels[this.getTagglyOpt(title,"sortOrder")];
onclick = function() {
config.taggly.toggleTagglyOpt(title,"sortOrder");
return false;
}
}
else {
onclick = function() {
config.taggly.setTagglyOpt(title,"sortBy",type);
config.taggly.setTagglyOpt(title,"sortOrder",config.taggly.config.listOpts.sortOrder[0]);
return false;
}
}
}
else {
// "regular" controls, nice and simple
label = lingo.labels[type == "numCols" ? type : this.getNextValue(title,type)];
tooltip = lingo.tooltips[type == "numCols" ? type : this.getNextValue(title,type)];
onclick = function() {
config.taggly.toggleTagglyOpt(title,type);
return false;
}
}
// hide button because commas don't have columns
if (!(this.getTagglyOpt(title,"listMode") == "commas" && type == "numCols"))
createTiddlyButton(place,label,tooltip,onclick,type == "hideState" ? "hidebutton" : "button");
},
makeColumns: function(orig,numCols) {
var listSize = orig.length;
var colSize = listSize/numCols;
var remainder = listSize % numCols;
var upperColsize = colSize;
var lowerColsize = colSize;
if (colSize != Math.floor(colSize)) {
// it's not an exact fit so..
upperColsize = Math.floor(colSize) + 1;
lowerColsize = Math.floor(colSize);
}
var output = [];
var c = 0;
for (var j=0;j<numCols;j++) {
var singleCol = [];
var thisSize = j < remainder ? upperColsize : lowerColsize;
for (var i=0;i<thisSize;i++)
singleCol.push(orig[c++]);
output.push(singleCol);
}
return output;
},
drawTable: function(place,columns,theClass) {
var newTable = createTiddlyElement(place,"table",null,theClass);
var newTbody = createTiddlyElement(newTable,"tbody");
var newTr = createTiddlyElement(newTbody,"tr");
for (var j=0;j<columns.length;j++) {
var colOutput = "";
for (var i=0;i<columns[j].length;i++)
colOutput += columns[j][i];
var newTd = createTiddlyElement(newTr,"td",null,"tagglyTagging"); // todo should not need this class
wikify(colOutput,newTd);
}
return newTable;
},
createTagglyList: function(place,title,isTagExpr) {
switch(this.getTagglyOpt(title,"listMode")) {
case "group": return this.createTagglyListGrouped(place,title,isTagExpr); break;
case "normal": return this.createTagglyListNormal(place,title,false,isTagExpr); break;
case "commas": return this.createTagglyListNormal(place,title,true,isTagExpr); break;
case "sitemap":return this.createTagglyListSiteMap(place,title,isTagExpr); break;
}
},
getTaggingCount: function(title,isTagExpr) {
// thanks to Doug Edmunds
if (this.config.showTaggingCounts) {
var tagCount = config.taggly.getTiddlers(title,'title',isTagExpr).length;
if (tagCount > 0)
return " ("+tagCount+")";
}
return "";
},
getTiddlers: function(titleOrExpr,sortBy,isTagExpr) {
return isTagExpr ? store.getTiddlersByTagExpr(titleOrExpr,sortBy) : store.getTaggedTiddlers(titleOrExpr,sortBy);
},
getExcerpt: function(inTiddlerTitle,title,indent) {
if (!indent)
indent = 1;
var displayMode = this.getTagglyOpt(inTiddlerTitle,"excerpts");
var t = store.getTiddler(title);
if (t && displayMode == "excerpts") {
var text = t.text.replace(/\n/," ");
var marker = text.indexOf(this.config.excerptMarker);
if (marker != -1) {
return " {{excerpt{<nowiki>" + text.substr(0,marker) + "</nowiki>}}}";
}
else if (text.length < this.config.excerptSize) {
return " {{excerpt{<nowiki>" + t.text + "</nowiki>}}}";
}
else {
return " {{excerpt{<nowiki>" + t.text.substr(0,this.config.excerptSize) + "..." + "</nowiki>}}}";
}
}
else if (t && displayMode == "contents") {
return "\n{{contents indent"+indent+"{\n" + t.text + "\n}}}";
}
else if (t && displayMode == "sliders") {
return "<slider slide>\n{{contents{\n" + t.text + "\n}}}\n</slider>";
}
else if (t && displayMode == "descr") {
var descr = store.getTiddlerSlice(title,'Description');
return descr ? " {{excerpt{" + descr + "}}}" : "";
}
else if (t && displayMode == "slices") {
var result = "";
var slices = store.calcAllSlices(title);
for (var s in slices)
result += "|%0|<nowiki>%1</nowiki>|\n".format([s,slices[s]]);
return result ? "\n{{excerpt excerptIndent{\n" + result + "}}}" : "";
}
return "";
},
notHidden: function(t,inTiddler) {
if (typeof t == "string")
t = store.getTiddler(t);
return (!t || !t.tags.containsAny(this.config.excludeTags) ||
(inTiddler && this.config.excludeTags.contains(inTiddler)));
},
// this is for normal and commas mode
createTagglyListNormal: function(place,title,useCommas,isTagExpr) {
var list = config.taggly.getTiddlers(title,this.getTagglyOpt(title,"sortBy"),isTagExpr);
if (this.getTagglyOpt(title,"sortOrder") == "desc")
list = list.reverse();
var output = [];
var first = true;
for (var i=0;i<list.length;i++) {
if (this.notHidden(list[i],title)) {
var countString = this.getTaggingCount(list[i].title);
var excerpt = this.getExcerpt(title,list[i].title);
if (useCommas)
output.push((first ? "" : ", ") + "[[" + list[i].title + "]]" + countString + excerpt);
else
output.push("*[[" + list[i].title + "]]" + countString + excerpt + "\n");
first = false;
}
}
return this.drawTable(place,
this.makeColumns(output,useCommas ? 1 : parseInt(this.getTagglyOpt(title,"numCols"))),
useCommas ? "commas" : "normal");
},
// this is for the "grouped" mode
createTagglyListGrouped: function(place,title,isTagExpr) {
var sortBy = this.getTagglyOpt(title,"sortBy");
var sortOrder = this.getTagglyOpt(title,"sortOrder");
var list = config.taggly.getTiddlers(title,sortBy,isTagExpr);
if (sortOrder == "desc")
list = list.reverse();
var leftOvers = []
for (var i=0;i<list.length;i++)
leftOvers.push(list[i].title);
var allTagsHolder = {};
for (var i=0;i<list.length;i++) {
for (var j=0;j<list[i].tags.length;j++) {
if (list[i].tags[j] != title) { // not this tiddler
if (this.notHidden(list[i].tags[j],title)) {
if (!allTagsHolder[list[i].tags[j]])
allTagsHolder[list[i].tags[j]] = "";
if (this.notHidden(list[i],title)) {
allTagsHolder[list[i].tags[j]] += "**[["+list[i].title+"]]"
+ this.getTaggingCount(list[i].title) + this.getExcerpt(title,list[i].title) + "\n";
leftOvers.setItem(list[i].title,-1); // remove from leftovers. at the end it will contain the leftovers
}
}
}
}
}
var allTags = [];
for (var t in allTagsHolder)
allTags.push(t);
var sortHelper = function(a,b) {
if (a == b) return 0;
if (a < b) return -1;
return 1;
};
allTags.sort(function(a,b) {
var tidA = store.getTiddler(a);
var tidB = store.getTiddler(b);
if (sortBy == "title") return sortHelper(a,b);
else if (!tidA && !tidB) return 0;
else if (!tidA) return -1;
else if (!tidB) return +1;
else return sortHelper(tidA[sortBy],tidB[sortBy]);
});
var leftOverOutput = "";
for (var i=0;i<leftOvers.length;i++)
if (this.notHidden(leftOvers[i],title))
leftOverOutput += "*[["+leftOvers[i]+"]]" + this.getTaggingCount(leftOvers[i]) + this.getExcerpt(title,leftOvers[i]) + "\n";
var output = [];
if (sortOrder == "desc")
allTags.reverse();
else if (leftOverOutput != "")
// leftovers first...
output.push(leftOverOutput);
for (var i=0;i<allTags.length;i++)
if (allTagsHolder[allTags[i]] != "")
output.push("*[["+allTags[i]+"]]" + this.getTaggingCount(allTags[i]) + this.getExcerpt(title,allTags[i]) + "\n" + allTagsHolder[allTags[i]]);
if (sortOrder == "desc" && leftOverOutput != "")
// leftovers last...
output.push(leftOverOutput);
return this.drawTable(place,
this.makeColumns(output,parseInt(this.getTagglyOpt(title,"numCols"))),
"grouped");
},
// used to build site map
treeTraverse: function(title,depth,sortBy,sortOrder,isTagExpr) {
var list = config.taggly.getTiddlers(title,sortBy,isTagExpr);
if (sortOrder == "desc")
list.reverse();
var indent = "";
for (var j=0;j<depth;j++)
indent += "*"
var childOutput = "";
if (depth > this.config.siteMapDepthLimit)
childOutput += indent + this.lingo.tooDeepMessage;
else
for (var i=0;i<list.length;i++)
if (list[i].title != title)
if (this.notHidden(list[i].title,this.config.inTiddler))
childOutput += this.treeTraverse(list[i].title,depth+1,sortBy,sortOrder,false);
if (depth == 0)
return childOutput;
else
return indent + "[["+title+"]]" + this.getTaggingCount(title) + this.getExcerpt(this.config.inTiddler,title,depth) + "\n" + childOutput;
},
// this if for the site map mode
createTagglyListSiteMap: function(place,title,isTagExpr) {
this.config.inTiddler = title; // nasty. should pass it in to traverse probably
var output = this.treeTraverse(title,0,this.getTagglyOpt(title,"sortBy"),this.getTagglyOpt(title,"sortOrder"),isTagExpr);
return this.drawTable(place,
this.makeColumns(output.split(/(?=^\*\[)/m),parseInt(this.getTagglyOpt(title,"numCols"))), // regexp magic
"sitemap"
);
},
macros: {
tagglyTagging: {
handler: function (place,macroName,params,wikifier,paramString,tiddler) {
var parsedParams = paramString.parseParams("tag",null,true);
var refreshContainer = createTiddlyElement(place,"div");
// do some refresh magic to make it keep the list fresh - thanks Saq
refreshContainer.setAttribute("refresh","macro");
refreshContainer.setAttribute("macroName",macroName);
var tag = getParam(parsedParams,"tag");
var expr = getParam(parsedParams,"expr");
if (expr) {
refreshContainer.setAttribute("isTagExpr","true");
refreshContainer.setAttribute("title",expr);
refreshContainer.setAttribute("showEmpty","true");
}
else {
refreshContainer.setAttribute("isTagExpr","false");
if (tag) {
refreshContainer.setAttribute("title",tag);
refreshContainer.setAttribute("showEmpty","true");
}
else {
refreshContainer.setAttribute("title",tiddler.title);
refreshContainer.setAttribute("showEmpty","false");
}
}
this.refresh(refreshContainer);
},
refresh: function(place) {
var title = place.getAttribute("title");
var isTagExpr = place.getAttribute("isTagExpr") == "true";
var showEmpty = place.getAttribute("showEmpty") == "true";
removeChildren(place);
addClass(place,"tagglyTagging");
var countFound = config.taggly.getTiddlers(title,'title',isTagExpr).length
if (countFound > 0 || showEmpty) {
var lingo = config.taggly.lingo;
config.taggly.createListControl(place,title,"hideState");
if (config.taggly.getTagglyOpt(title,"hideState") == "show") {
createTiddlyElement(place,"span",null,"tagglyLabel",
isTagExpr ? lingo.labels.exprLabel.format([title]) : lingo.labels.label.format([title]));
config.taggly.createListControl(place,title,"title");
config.taggly.createListControl(place,title,"modified");
config.taggly.createListControl(place,title,"created");
config.taggly.createListControl(place,title,"listMode");
config.taggly.createListControl(place,title,"excerpts");
config.taggly.createListControl(place,title,"numCols");
config.taggly.createTagglyList(place,title,isTagExpr);
if (countFound == 0 && showEmpty)
createTiddlyElement(place,"div",null,"tagglyNoneFound",lingo.labels.noneFound);
}
}
}
}
},
// todo fix these up a bit
styles: [
"/*{{{*/",
"/* created by TagglyTaggingPlugin */",
".tagglyTagging { padding-top:0.5em; }",
".tagglyTagging li.listTitle { display:none; }",
".tagglyTagging ul {",
" margin-top:0px; padding-top:0.5em; padding-left:2em;",
" margin-bottom:0px; padding-bottom:0px;",
"}",
".tagglyTagging { vertical-align: top; margin:0px; padding:0px; }",
".tagglyTagging table { margin:0px; padding:0px; }",
".tagglyTagging .button { visibility:hidden; margin-left:3px; margin-right:3px; }",
".tagglyTagging .button, .tagglyTagging .hidebutton {",
" color:[[ColorPalette::TertiaryLight]]; font-size:90%;",
" border:0px; padding-left:0.3em;padding-right:0.3em;",
"}",
".tagglyTagging .button:hover, .hidebutton:hover, ",
".tagglyTagging .button:active, .hidebutton:active {",
" border:0px; background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]];",
"}",
".selected .tagglyTagging .button { visibility:visible; }",
".tagglyTagging .hidebutton { color:[[ColorPalette::Background]]; }",
".selected .tagglyTagging .hidebutton { color:[[ColorPalette::TertiaryLight]] }",
".tagglyLabel { color:[[ColorPalette::TertiaryMid]]; font-size:90%; }",
".tagglyTagging ul {padding-top:0px; padding-bottom:0.5em; margin-left:1em; }",
".tagglyTagging ul ul {list-style-type:disc; margin-left:-1em;}",
".tagglyTagging ul ul li {margin-left:0.5em; }",
".editLabel { font-size:90%; padding-top:0.5em; }",
".tagglyTagging .commas { padding-left:1.8em; }",
"/* not technically tagglytagging but will put them here anyway */",
".tagglyTagged li.listTitle { display:none; }",
".tagglyTagged li { display: inline; font-size:90%; }",
".tagglyTagged ul { margin:0px; padding:0px; }",
".excerpt { color:[[ColorPalette::TertiaryDark]]; }",
".excerptIndent { margin-left:4em; }",
"div.tagglyTagging table,",
"div.tagglyTagging table tr,",
"td.tagglyTagging",
" {border-style:none!important; }",
".tagglyTagging .contents { border-bottom:2px solid [[ColorPalette::TertiaryPale]]; padding:0 1em 1em 0.5em;",
" margin-bottom:0.5em; }",
".tagglyTagging .indent1 { margin-left:3em; }",
".tagglyTagging .indent2 { margin-left:4em; }",
".tagglyTagging .indent3 { margin-left:5em; }",
".tagglyTagging .indent4 { margin-left:6em; }",
".tagglyTagging .indent5 { margin-left:7em; }",
".tagglyTagging .indent6 { margin-left:8em; }",
".tagglyTagging .indent7 { margin-left:9em; }",
".tagglyTagging .indent8 { margin-left:10em; }",
".tagglyTagging .indent9 { margin-left:11em; }",
".tagglyTagging .indent10 { margin-left:12em; }",
".tagglyNoneFound { margin-left:2em; color:[[ColorPalette::TertiaryMid]]; font-size:90%; font-style:italic; }",
"/*}}}*/",
""].join("\n"),
init: function() {
merge(config.macros,this.macros);
config.shadowTiddlers["TagglyTaggingStyles"] = this.styles;
store.addNotification("TagglyTaggingStyles",refreshStyles);
}
};
config.taggly.init();
//}}}
/***
InlineSlidersPlugin
By Saq Imtiaz
http://tw.lewcid.org/sandbox/#InlineSlidersPlugin
// syntax adjusted to not clash with NestedSlidersPlugin
// added + syntax to start open instead of closed
***/
//{{{
config.formatters.unshift( {
name: "inlinesliders",
// match: "\\+\\+\\+\\+|\\<slider",
match: "\\<slider",
// lookaheadRegExp: /(?:\+\+\+\+|<slider) (.*?)(?:>?)\n((?:.|\n)*?)\n(?:====|<\/slider>)/mg,
lookaheadRegExp: /(?:<slider)(\+?) (.*?)(?:>)\n((?:.|\n)*?)\n(?:<\/slider>)/mg,
handler: function(w) {
this.lookaheadRegExp.lastIndex = w.matchStart;
var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
if(lookaheadMatch && lookaheadMatch.index == w.matchStart ) {
var btn = createTiddlyButton(w.output,lookaheadMatch[2] + " "+"\u00BB",lookaheadMatch[2],this.onClickSlider,"button sliderButton");
var panel = createTiddlyElement(w.output,"div",null,"sliderPanel");
panel.style.display = (lookaheadMatch[1] == '+' ? "block" : "none");
wikify(lookaheadMatch[3],panel);
w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
}
},
onClickSlider : function(e) {
if(!e) var e = window.event;
var n = this.nextSibling;
n.style.display = (n.style.display=="none") ? "block" : "none";
return false;
}
});
//}}}
/***
|Name|TiddlerTweakerPlugin|
|Source|http://www.TiddlyTools.com/#TiddlerTweakerPlugin|
|Version|2.4.2|
|Author|Eric Shulman|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|plugin|
|Requires||
|Overrides||
|Description|select multiple tiddlers and modify author, created, modified and/or tag values|
~TiddlerTweaker is a tool for TiddlyWiki authors. It allows you to select multiple tiddlers from a listbox, either by direct interaction or automatically matching specific criteria. You can then modify the creator, author, created, modified and/or tag values of those tiddlers using a compact set of form fields. The values you enter into the fields simultantously overwrite the existing values in all tiddlers you have selected.
!!!!!Usage
<<<
{{{<<tiddlerTweaker>>}}}
{{smallform{<<tiddlerTweaker>>}}}
By default, any tags you enter into the TiddlerTweaker will //replace// the existing tags in all the tiddlers you have selected. However, you can also use TiddlerTweaker to quickly filter specified tags from the selected tiddlers, while leaving any other tags assigned to those tiddlers unchanged:
>Any tag preceded by a "+" (plus) or "-" (minus), will be added or removed from the existing tags //instead of replacing the entire tag definition// of each tiddler (e.g., enter "-excludeLists" to remove that tag from all selected tiddlers. When using this syntax, care should be taken to ensure that //every// tag is preceded by "+" or "-", to avoid inadvertently overwriting any other existing tags on the selected tiddlers. (note: the "+" or "-" prefix on each tag value is NOT part of the tag value, and is only used by TiddlerTweaker to control how that tag value is processed)
Important Notes:
* Inasmuch as TiddlerTweaker is a 'power user' tool that can perform 'batch' functions (operating on many tiddlers at once), you should always have a recent backup of your document (or "save changes" just *before* tweaking the tiddlers), just in case you "shoot yourself in the foot".
* The date and author information on any tiddlers you tweak will ONLY be updated if the corresponding TiddlyTweaker checkboxes have been selected. As a general rule, after using TiddlerTweaker, always ''//remember to save your document//'' when you are done, even though the tiddler timeline tab may not show any recently modified tiddlers.
* Selecting and updating all tiddlers in a document can take a while. Your browser may warn about an "unresponsive script". Usually, if you allow it to continue, it should complete the processing... eventually. Nonetheless, be sure to save your work before you begin tweaking lots of tiddlers, just in case something does get 'stuck'.
<<<
!!!!!Revisions
<<<
2009.06.26 [2.4.2] only add brackets around tags containing spaces
2009.06.22 [2.4.1] in setFields(), add brackets around all tags shown tweaker edit field
2009.03.30 [2.4.0] added 'sort by modifier'
2009.01.22 [2.3.0] added support for text pattern find/replace
2008.10.27 [2.2.3] in setTiddlers(), fixed Safari bug by replacing static Array.concat(...) with new Array().concat(...)
2008.09.07 [2.2.2] added removeCookie() function for compatibility with [[CookieManagerPlugin]]
2008.05.12 [2.2.1] replace built-in backstage "tweak" task with tiddler tweaker control panel (moved from BackstageTweaks)
2008.01.13 [2.2.0] added "auto-selection" links: all, changed, tags, title, text
2007.12.26 [2.1.0] added support for managing 'creator' custom field (see [[CoreTweaks]])
2007.11.01 [2.0.3] added config.options.txtTweakerSortBy for cookie-based persistence of list display order preference setting.
2007.09.28 [2.0.2] in settiddlers() and deltiddlers(), added suspend/resume notification handling (improves performance when operating on multiple tiddlers)
2007.08.03 [2.0.1] added shadow definition for [[TiddlerTweaker]] tiddler for use as parameter references with {{{<<tiddler>>, <<slider>> or <<tabs>>}}} macros.
2007.08.03 [2.0.0] converted from inline script
2006.01.01 [1.0.0] initial release
<<<
!!!!!Code
***/
//{{{
version.extensions.TiddlerTweakerPlugin= {major: 2, minor: 4, revision: 1, date: new Date(2009,6,22)};
// shadow tiddler
config.shadowTiddlers.TiddlerTweaker="<<tiddlerTweaker>>";
/// backstage task
if (config.tasks) { // for TW2.2b3 or above
config.tasks.tweak.tooltip="review/modify tiddler internals: dates, authors, tags, etc.";
config.tasks.tweak.content="{{smallform small groupbox{<<tiddlerTweaker>>}}}";
}
if (config.options.txtTweakerSortBy==undefined) config.options.txtTweakerSortBy="modified";
// if removeCookie() function is not defined by TW core, define it here.
if (window.removeCookie===undefined) {
window.removeCookie=function(name) {
document.cookie = name+'=; expires=Thu, 01-Jan-1970 00:00:01 UTC; path=/;';
}
}
config.macros.tiddlerTweaker = {
html: '<form style="display:inline"><!--\
--><table style="padding:0;margin:0;border:0;width:100%"><tr valign="top" style="padding:0;margin:0;border:0"><!--\
--><td style="text-align:center;white-space:nowrap;width:99%;padding:0;margin:0;border:0"><!--\
--><font size=-2><div style="text-align:left;"><span style="float:right"><!--\
--> <a href="javascript:;" \
title="select all tiddlers"\
onclick="\
var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
for (var t=0; t<f.list.options.length; t++)\
if (f.list.options[t].value.length) f.list.options[t].selected=true;\
config.macros.tiddlerTweaker.selecttiddlers(f.list);\
return false">all</a><!--\
--> <a href="javascript:;" \
title="select tiddlers that are new/changed since the last file save"\
onclick="\
var lastmod=new Date(document.lastModified);\
var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
for (var t=0; t<f.list.options.length; t++) {\
var tid=store.getTiddler(f.list.options[t].value);\
f.list.options[t].selected=tid&&tid.modified>lastmod;\
}\
config.macros.tiddlerTweaker.selecttiddlers(f.list);\
return false">changed</a><!--\
--> <a href="javascript:;" \
title="select tiddlers with at least one matching tag"\
onclick="\
var t=prompt(\'Enter space-separated tags (match ONE)\');\
if (!t||!t.length) return false;\
var tags=t.readBracketedList();\
var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
for (var t=0; t<f.list.options.length; t++) {\
f.list.options[t].selected=false;\
var tid=store.getTiddler(f.list.options[t].value);\
if (tid&&tid.tags.containsAny(tags)) f.list.options[t].selected=true;\
}\
config.macros.tiddlerTweaker.selecttiddlers(f.list);\
return false">tags</a><!--\
--> <a href="javascript:;" \
title="select tiddlers whose titles include matching text"\
onclick="\
var txt=prompt(\'Enter a title (or portion of a title) to match\');\
if (!txt||!txt.length) return false;\
var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
for (var t=0; t<f.list.options.length; t++) {\
f.list.options[t].selected=f.list.options[t].value.indexOf(txt)!=-1;\
}\
config.macros.tiddlerTweaker.selecttiddlers(f.list);\
return false">titles</a><!--\
--> <a href="javascript:;" \
title="select tiddlers containing matching text"\
onclick="\
var txt=prompt(\'Enter tiddler text (content) to match\');\
if (!txt||!txt.length) return false;\
var f=this; while (f&&f.nodeName.toLowerCase()!=\'form\')f=f.parentNode;\
for (var t=0; t<f.list.options.length; t++) {\
var tt=store.getTiddlerText(f.list.options[t].value,\'\');\
f.list.options[t].selected=(tt.indexOf(txt)!=-1);\
}\
config.macros.tiddlerTweaker.selecttiddlers(f.list);\
return false">text</a> <!--\
--></span><span>select tiddlers</span><!--\
--></div><!--\
--></font><select multiple name=list size="11" style="width:99.99%" \
title="use click, shift-click and/or ctrl-click to select multiple tiddler titles" \
onclick="config.macros.tiddlerTweaker.selecttiddlers(this)" \
onchange="config.macros.tiddlerTweaker.setfields(this)"><!--\
--></select><br><!--\
-->show<input type=text size=1 value="11" \
onchange="this.form.list.size=this.value; this.form.list.multiple=(this.value>1);"><!--\
-->by<!--\
--><select name=sortby size=1 \
onchange="config.macros.tiddlerTweaker.init(this.form,this.value)"><!--\
--><option value="title">title</option><!--\
--><option value="size">size</option><!--\
--><option value="modified">modified</option><!--\
--><option value="created">created</option><!--\
--><option value="modifier">modifier</option><!--\
--></select><!--\
--><input type="button" value="refresh" \
onclick="config.macros.tiddlerTweaker.init(this.form,this.form.sortby.value)"<!--\
--> <input type="button" name="stats" disabled value="totals..." \
onclick="config.macros.tiddlerTweaker.stats(this)"><!--\
--></td><td style="white-space:nowrap;padding:0;margin:0;border:0;width:1%"><!--\
--><div style="text-align:left"><font size=-2> modify values</font></div><!--\
--><table border=0 style="width:100%;padding:0;margin:0;border:0;"><tr style="padding:0;border:0;"><!--\
--><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=settitle unchecked \
title="allow changes to tiddler title (rename tiddler)" \
onclick="this.form.title.disabled=!this.checked">title<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=title size=35 style="width:98%" disabled><!--\
--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=setcreator unchecked \
title="allow changes to tiddler creator" \
onclick="this.form.creator.disabled=!this.checked">created by<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=creator size=35 style="width:98%" disabled><!--\
--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=setwho unchecked \
title="allow changes to tiddler author" \
onclick="this.form.who.disabled=!this.checked">modified by<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=who size=35 style="width:98%" disabled><!--\
--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=setcdate unchecked \
title="allow changes to created date" \
onclick="var f=this.form; f.cm.disabled=f.cd.disabled=f.cy.disabled=f.ch.disabled=f.cn.disabled=!this.checked"><!--\
-->created on<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=cm size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--> / <input type=text name=cd size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--> / <input type=text name=cy size=4 style="width:3em;padding:0;text-align:center" disabled><!--\
--> at <input type=text name=ch size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--> : <input type=text name=cn size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=setmdate unchecked \
title="allow changes to modified date" \
onclick="var f=this.form; f.mm.disabled=f.md.disabled=f.my.disabled=f.mh.disabled=f.mn.disabled=!this.checked"><!--\
-->modified on<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=mm size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--> / <input type=text name=md size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--> / <input type=text name=my size=4 style="width:3em;padding:0;text-align:center" disabled><!--\
--> at <input type=text name=mh size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--> : <input type=text name=mn size=2 style="width:2em;padding:0;text-align:center" disabled><!--\
--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=replacetext unchecked\
title="find/replace matching text" \
onclick="this.form.pattern.disabled=this.form.replacement.disabled=!this.checked">replace text<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=pattern size=15 value="" style="width:40%" disabled \
title="enter TEXT PATTERN (regular expression)"> with <!--\
--><input type=text name=replacement size=15 value="" style="width:40%" disabled \
title="enter REPLACEMENT TEXT"><!--\
--></td></tr><tr style="padding:0;border:0;"><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=checkbox name=settags checked \
title="allow changes to tiddler tags" \
onclick="this.form.tags.disabled=!this.checked">tags<!--\
--></td><td style="padding:1px;border:0;white-space:nowrap"><!--\
--><input type=text name=tags size=35 value="" style="width:98%" \
title="enter new tags or use \'+tag\' and \'-tag\' to add/remove tags from existing tags"><!--\
--></td></tr></table><!--\
--><div style="text-align:center"><!--\
--><nobr><input type=button name=display disabled style="width:32%" value="display tiddlers" \
onclick="config.macros.tiddlerTweaker.displaytiddlers(this)"><!--\
--> <input type=button name=del disabled style="width:32%" value="delete tiddlers" \
onclick="config.macros.tiddlerTweaker.deltiddlers(this)"><!--\
--> <input type=button name=set disabled style="width:32%" value="update tiddlers" \
onclick="config.macros.tiddlerTweaker.settiddlers(this)"></nobr><!--\
--></div><!--\
--></td></tr></table><!--\
--></form><span style="display:none"><!--content replaced by tiddler "stats"--></span>\
',
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var span=createTiddlyElement(place,"span");
span.innerHTML=this.html;
this.init(span.firstChild,config.options.txtTweakerSortBy);
},
init: function(f,sortby) { // initialize form controls
if (!f) return; // form might not be rendered yet...
while (f.list.options[0]) f.list.options[0]=null; // empty current list content
var tids=store.getTiddlers(sortby);
if (sortby=='size') // descending order
tids.sort(function(a,b) {return a.text.length > b.text.length ? -1 : (a.text.length == b.text.length ? 0 : +1);});
var who='';
for (i=0; i<tids.length; i++) { var t=tids[i];
var label=t.title; var value=t.title;
switch (sortby) {
case 'modified':
case 'created':
var t=tids[tids.length-i-1]; // reverse order
var when=t[sortby].formatString('YY.0MM.0DD 0hh:0mm ');
label=when+t.title;
value=t.title;
break;
case 'size':
label='['+t.text.length+'] '+label;
break;
case 'modifier':
case 'creator':
if (who!=t[sortby]) {
who=t[sortby];
f.list.options[f.list.length]=new Option('by '+who+':','',false,false);
}
label='\xa0\xa0\xa0'+label; // indent
break;
}
f.list.options[f.list.length]=new Option(label,value,false,false);
}
f.title.value=f.who.value=f.creator.value=f.tags.value="";
f.cm.value=f.cd.value=f.cy.value=f.ch.value=f.cn.value="";
f.mm.value=f.md.value=f.my.value=f.mh.value=f.mn.value="";
f.stats.disabled=f.set.disabled=f.del.disabled=f.display.disabled=true;
f.settitle.disabled=false;
config.options.txtTweakerSortBy=sortby; // remember current setting
f.sortby.value=sortby; // sync droplist selection with current setting
if (sortby!="modified") // non-default preference... save cookie
saveOptionCookie("txtTweakerSortBy");
else removeCookie("txtTweakerSortBy"); // default preference... clear cookie
},
selecttiddlers: function(here) { // enable/disable tweaker fields based on number of items selected
// count how many tiddlers are selected
var f=here.form; var list=f.list;
var c=0; for (i=0;i<list.length;i++) if (list.options[i].selected) c++;
if (c>1) f.title.disabled=true;
if (c>1) f.settitle.checked=false;
f.set.disabled=(c==0);
f.del.disabled=(c==0);
f.display.disabled=(c==0);
f.settitle.disabled=(c>1);
f.stats.disabled=(c==0);
var msg=(c==0)?'select tiddlers':(c+' tiddler'+(c!=1?'s':'')+' selected');
here.previousSibling.firstChild.firstChild.nextSibling.innerHTML=msg;
if (c) clearMessage(); else displayMessage("no tiddlers selected");
},
setfields: function(here) { // set tweaker edit fields from first selected tiddler
var f=here.form;
if (!here.value.length) {
f.title.value=f.who.value=f.creator.value=f.tags.value="";
f.cm.value=f.cd.value=f.cy.value=f.ch.value=f.cn.value="";
f.mm.value=f.md.value=f.my.value=f.mh.value=f.mn.value="";
return;
}
var tid=store.getTiddler(here.value); if (!tid) return;
f.title.value=tid.title;
f.who.value=tid.modifier;
f.creator.value=tid.fields['creator']||''; // custom field - might not exist
f.tags.value=tid.tags.map(function(t){return String.encodeTiddlyLink(t)}).join(' ');
var c=tid.created; var m=tid.modified;
f.cm.value=c.getMonth()+1;
f.cd.value=c.getDate();
f.cy.value=c.getFullYear();
f.ch.value=c.getHours();
f.cn.value=c.getMinutes();
f.mm.value=m.getMonth()+1;
f.md.value=m.getDate();
f.my.value=m.getFullYear();
f.mh.value=m.getHours();
f.mn.value=m.getMinutes();
},
settiddlers: function(here) {
var f=here.form; var list=f.list;
var tids=[];
for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
if (!tids.length) { alert("please select at least one tiddler"); return; }
var cdate=new Date(f.cy.value,f.cm.value-1,f.cd.value,f.ch.value,f.cn.value);
var mdate=new Date(f.my.value,f.mm.value-1,f.md.value,f.mh.value,f.mn.value);
if (tids.length>1 && !confirm("Are you sure you want to update these tiddlers:\n\n"+tids.join(', '))) return;
store.suspendNotifications();
for (t=0;t<tids.length;t++) {
var tid=store.getTiddler(tids[t]); if (!tid) continue;
var title=!f.settitle.checked?tid.title:f.title.value;
var who=!f.setwho.checked?tid.modifier:f.who.value;
var text=tid.text;
if (f.replacetext.checked) text=text.replace(new RegExp(f.pattern.value,'mg'),f.replacement.value);
var tags=tid.tags;
if (f.settags.checked) {
var intags=f.tags.value.readBracketedList();
var addtags=[]; var deltags=[]; var reptags=[];
for (i=0;i<intags.length;i++) {
if (intags[i].substr(0,1)=='+')
addtags.push(intags[i].substr(1));
else if (intags[i].substr(0,1)=='-')
deltags.push(intags[i].substr(1));
else
reptags.push(intags[i]);
}
if (reptags.length)
tags=reptags;
if (addtags.length)
tags=new Array().concat(tags,addtags);
if (deltags.length)
for (i=0;i<deltags.length;i++)
{ var pos=tags.indexOf(deltags[i]); if (pos!=-1) tags.splice(pos,1); }
}
if (!f.setcdate.checked) cdate=tid.created;
if (!f.setmdate.checked) mdate=tid.modified;
store.saveTiddler(tid.title,title,text,who,mdate,tags,tid.fields);
if (f.setcreator.checked) store.setValue(tid.title,'creator',f.creator.value); // set creator
if (f.setcdate.checked) tid.assign(null,null,null,null,null,cdate); // set create date
}
store.resumeNotifications();
this.init(f,f.sortby.value);
},
displaytiddlers: function(here) {
var f=here.form; var list=f.list;
var tids=[];
for (i=0; i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
if (!tids.length) { alert("please select at least one tiddler"); return; }
story.displayTiddlers(story.findContainingTiddler(f),tids)
},
deltiddlers: function(here) {
var f=here.form; var list=f.list;
var tids=[];
for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
if (!tids.length) { alert("please select at least one tiddler"); return; }
if (!confirm("Are you sure you want to delete these tiddlers:\n\n"+tids.join(', '))) return;
store.suspendNotifications();
for (t=0;t<tids.length;t++) {
var tid=store.getTiddler(tids[t]); if (!tid) continue;
if (tid.tags.contains("systemConfig"))
if (!confirm("'"+tid.title+"' is tagged with 'systemConfig'.\n\nRemoving this tiddler may cause unexpected results. Are you sure?"))
continue;
store.removeTiddler(tid.title);
story.closeTiddler(tid.title);
}
store.resumeNotifications();
this.init(f,f.sortby.value);
},
stats: function(here) {
var f=here.form; var list=f.list; var tids=[]; var out=''; var tot=0;
var target=f.nextSibling;
for (i=0;i<list.length;i++) if (list.options[i].selected) tids.push(list.options[i].value);
if (!tids.length) { alert("please select at least one tiddler"); return; }
for (t=0;t<tids.length;t++) {
var tid=store.getTiddler(tids[t]); if (!tid) continue;
out+='[['+tid.title+']] '+tid.text.length+'\n'; tot+=tid.text.length;
}
var avg=tot/tids.length;
out=tot+' bytes in '+tids.length+' selected tiddlers ('+avg+' bytes/tiddler)\n<<<\n'+out+'<<<\n';
removeChildren(target);
target.innerHTML="<hr><font size=-2><a href='javascript:;' style='float:right' "
+"onclick='this.parentNode.parentNode.style.display=\"none\"'>close</a></font>";
wikify(out,target);
target.style.display="block";
}
};
//}}}
/%
|Name|ToggleRightSidebar|
|Source|http://www.TiddlyTools.com/#ToggleRightSidebar|
|Version|2.0.0|
|Author|Eric Shulman - ELS Design Studios|
|License|http://www.TiddlyTools.com/#LegalStatements <br>and [[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|~CoreVersion|2.1|
|Type|script|
|Requires|InlineJavascriptPlugin|
|Overrides||
|Description|show/hide right sidebar (MainMenu)|
Usage: <<tiddler ToggleRightSidebar with: "label">>
Config settings:
config.options.chkShowRightSidebar (true)
config.options.txtToggleRightSideBarLabelShow (â—„)
config.options.txtToggleRightSideBarLabelHide (â–º)
%/<script label="$1" title="show/hide right sidebar content">
var co=config.options;
if (co.chkShowRightSidebar=='undefined') co.chkShowRightSidebar=true;
co.chkShowRightSidebar=!co.chkShowRightSidebar;
var sb=document.getElementById('sidebar'); if (!sb) return;
sb.style.display=co.chkShowRightSidebar?'block':'none';
document.getElementById('displayArea').style.marginRight=co.chkShowRightSidebar?'':'1em';
saveOptionCookie('chkShowRightSidebar');
var labelShow=co.txtToggleRightSideBarLabelShow||'◄';
var labelHide=co.txtToggleRightSideBarLabelHide||'►';
if (typeof(place)!='undefined' && '$1'=='$'+'1') {
place.innerHTML=co.chkShowRightSidebar?labelHide:labelShow;
place.title=(co.chkShowRightSidebar?'hide':'show')+' right sidebar';
}
var sm=document.getElementById('storyMenu'); if (sm) config.refreshers.content(sm);
</script><script>
var co=config.options;
if (co.chkShowRightSidebar=='undefined') co.chkShowRightSidebar=true;
var sb=document.getElementById('sidebar'); if (!sb) return;
sb.style.display=co.chkShowRightSidebar?'block':'none';
document.getElementById('displayArea').style.marginRight=co.chkShowRightSidebar?'':'1em';
if ('$1'=='$'+'1') {
var labelShow=co.txtToggleRightSideBarLabelShow||'◄';
var labelHide=co.txtToggleRightSideBarLabelHide||'►';
place.lastChild.innerHTML=co.chkShowRightSidebar?labelHide:labelShow;
place.lastChild.title=(co.chkShowRightSidebar?'hide':'show')+' right sidebar';
}
</script>
/***
|Name:|ToggleTagPlugin|
|Description:|Makes a checkbox which toggles a tag in a tiddler|
|Version:|3.1.0 ($Rev: 4907 $)|
|Date:|$Date: 2008-05-13 03:15:46 +1000 (Tue, 13 May 2008) $|
|Source:|http://mptw.tiddlyspot.com/#ToggleTagPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
!!Usage
{{{<<toggleTag }}}//{{{TagName TiddlerName LabelText}}}//{{{>>}}}
* TagName - the tag to be toggled, default value "checked"
* TiddlerName - the tiddler to toggle the tag in, default value the current tiddler
* LabelText - the text (gets wikified) to put next to the check box, default value is '{{{[[TagName]]}}}' or '{{{[[TagName]] [[TiddlerName]]}}}'
(If a parameter is '.' then the default will be used)
* TouchMod flag - if non empty then touch the tiddlers mod date. Note, can set config.toggleTagAlwaysTouchModDate to always touch mod date
!!Examples
|Code|Description|Example|h
|{{{<<toggleTag>>}}}|Toggles the default tag (checked) in this tiddler|<<toggleTag>>|
|{{{<<toggleTag TagName>>}}}|Toggles the TagName tag in this tiddler|<<toggleTag TagName>>|
|{{{<<toggleTag TagName TiddlerName>>}}}|Toggles the TagName tag in the TiddlerName tiddler|<<toggleTag TagName TiddlerName>>|
|{{{<<toggleTag TagName TiddlerName 'click me'>>}}}|Same but with custom label|<<toggleTag TagName TiddlerName 'click me'>>|
|{{{<<toggleTag . . 'click me'>>}}}|dot means use default value|<<toggleTag . . 'click me'>>|
!!Notes
* If TiddlerName doesn't exist it will be silently created
* Set label to '-' to specify no label
* See also http://mgtd-alpha.tiddlyspot.com/#ToggleTag2
!!Known issues
* Doesn't smoothly handle the case where you toggle a tag in a tiddler that is current open for editing
* Should convert to use named params
***/
//{{{
if (config.toggleTagAlwaysTouchModDate == undefined) config.toggleTagAlwaysTouchModDate = false;
merge(config.macros,{
toggleTag: {
createIfRequired: true,
shortLabel: "[[%0]]",
longLabel: "[[%0]] [[%1]]",
handler: function(place,macroName,params,wikifier,paramString,tiddler) {
var tiddlerTitle = tiddler ? tiddler.title : '';
var tag = (params[0] && params[0] != '.') ? params[0] : "checked";
var title = (params[1] && params[1] != '.') ? params[1] : tiddlerTitle;
var defaultLabel = (title == tiddlerTitle ? this.shortLabel : this.longLabel);
var label = (params[2] && params[2] != '.') ? params[2] : defaultLabel;
var touchMod = (params[3] && params[3] != '.') ? params[3] : "";
label = (label == '-' ? '' : label); // dash means no label
var theTiddler = (title == tiddlerTitle ? tiddler : store.getTiddler(title));
var cb = createTiddlyCheckbox(place, label.format([tag,title]), theTiddler && theTiddler.isTagged(tag), function(e) {
if (!store.tiddlerExists(title)) {
if (config.macros.toggleTag.createIfRequired) {
var content = store.getTiddlerText(title); // just in case it's a shadow
store.saveTiddler(title,title,content?content:"",config.options.txtUserName,new Date(),null);
}
else
return false;
}
if ((touchMod != "" || config.toggleTagAlwaysTouchModDate) && theTiddler)
theTiddler.modified = new Date();
store.setTiddlerTag(title,this.checked,tag);
return true;
});
}
}
});
//}}}
/***
Description: Contains the stuff you need to use Tiddlyspot
Note, you also need UploadPlugin, PasswordOptionPlugin and LoadRemoteFileThroughProxy
from http://tiddlywiki.bidix.info for a complete working Tiddlyspot site.
***/
//{{{
// edit this if you are migrating sites or retrofitting an existing TW
config.tiddlyspotSiteId = 'tiddlysquat';
// make it so you can by default see edit controls via http
config.options.chkHttpReadOnly = false;
window.readOnly = false; // make sure of it (for tw 2.2)
window.showBackstage = true; // show backstage too
// disable autosave in d3
if (window.location.protocol != "file:")
config.options.chkGTDLazyAutoSave = false;
// tweak shadow tiddlers to add upload button, password entry box etc
with (config.shadowTiddlers) {
SiteUrl = 'http://'+config.tiddlyspotSiteId+'.tiddlyspot.com';
SideBarOptions = SideBarOptions.replace(/(<<saveChanges>>)/,"$1<<tiddler TspotSidebar>>");
OptionsPanel = OptionsPanel.replace(/^/,"<<tiddler TspotOptions>>");
DefaultTiddlers = DefaultTiddlers.replace(/^/,"[[WelcomeToTiddlyspot]] ");
MainMenu = MainMenu.replace(/^/,"[[WelcomeToTiddlyspot]] ");
}
// create some shadow tiddler content
merge(config.shadowTiddlers,{
'WelcomeToTiddlyspot':[
"This document is a ~TiddlyWiki from tiddlyspot.com. A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //What now?// @@ Before you can save any changes, you need to enter your password in the form below. Then configure privacy and other site settings at your [[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]] (your control panel username is //" + config.tiddlyspotSiteId + "//).",
"<<tiddler TspotControls>>",
"See also GettingStarted.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Working online// @@ You can edit this ~TiddlyWiki right now, and save your changes using the \"save to web\" button in the column on the right.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// @@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick. You can make changes and save them locally without being connected to the Internet. When you're ready to sync up again, just click \"upload\" and your ~TiddlyWiki will be saved back to tiddlyspot.com.",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Help!// @@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]]. Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help. If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].",
"",
"@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// @@ We hope you like using your tiddlyspot.com site. Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions."
].join("\n"),
'TspotControls':[
"| tiddlyspot password:|<<option pasUploadPassword>>|",
"| site management:|<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . . " + config.tiddlyspotSiteId + ">>//(requires tiddlyspot password)//<br>[[control panel|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/controlpanel]], [[download (go offline)|http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download]]|",
"| links:|[[tiddlyspot.com|http://tiddlyspot.com/]], [[FAQs|http://faq.tiddlyspot.com/]], [[blog|http://tiddlyspot.blogspot.com/]], email [[support|mailto:support@tiddlyspot.com]] & [[feedback|mailto:feedback@tiddlyspot.com]], [[donate|http://tiddlyspot.com/?page=donate]]|"
].join("\n"),
'TspotSidebar':[
"<<upload http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/store.cgi index.html . . " + config.tiddlyspotSiteId + ">><html><a href='http://" + config.tiddlyspotSiteId + ".tiddlyspot.com/download' class='button'>download</a></html>"
].join("\n"),
'TspotOptions':[
"tiddlyspot password:",
"<<option pasUploadPassword>>",
""
].join("\n")
});
//}}}
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 24/07/2009 13:21:18 | SteveW | [[/|http://mptwcadfael.tiddlyspot.com/]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . |
| 24/07/2009 17:13:42 | SteveW | [[/|http://mptwcadfael.tiddlyspot.com/]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . |
| 24/07/2009 18:48:59 | sww | [[/|http://mptwcadfael.tiddlyspot.com/]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . |
| 24/07/2009 18:54:29 | sww | [[/|http://mptwcadfael.tiddlyspot.com/]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . | ok |
| 24/07/2009 19:00:24 | sww | [[/|http://mptwcadfael.tiddlyspot.com/]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . | ok |
| 24/07/2009 19:07:43 | sww | [[/|http://mptwcadfael.tiddlyspot.com/]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . |
| 24/07/2009 19:20:29 | sww | [[tiddlysquat.html|file:///Users/steve/Desktop/tiddlysquat.html]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . | failed |
| 24/07/2009 19:22:05 | sww | [[tiddlysquat.html|file:///Users/steve/Desktop/tiddlysquat.html]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . |
| 24/07/2009 19:26:31 | sww | [[tiddlysquat.html|file:///Users/steve/Desktop/tiddlysquat.html]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . | failed |
| 24/07/2009 19:56:20 | sww | [[tiddlysquat.html|file:///Users/steve/Desktop/tiddlysquat.html]] | [[store.cgi|http://mptwcadfael.tiddlyspot.com/store.cgi]] | . | [[index.html | http://mptwcadfael.tiddlyspot.com/index.html]] | . |
/***
|''Name:''|UploadPlugin|
|''Description:''|Save to web a TiddlyWiki|
|''Version:''|4.1.3|
|''Date:''|Feb 24, 2008|
|''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|
|''Requires:''|PasswordOptionPlugin|
***/
//{{{
version.extensions.UploadPlugin = {
major: 4, minor: 1, revision: 3,
date: new Date("Feb 24, 2008"),
source: 'http://tiddlywiki.bidix.info/#UploadPlugin',
author: 'BidiX (BidiX (at) bidix (dot) info',
coreVersion: '2.2.0'
};
//
// 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
if (!params) params = {};
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}
]);
},
options: [
"txtUploadUserName",
"pasUploadPassword",
"txtUploadStoreUrl",
"txtUploadDir",
"txtUploadFilename",
"txtUploadBackupDir",
"chkUploadLog",
"txtUploadLogMaxLine"
],
refreshOptions: function(listWrapper) {
var opts = [];
for(i=0; i<this.options.length; i++) {
var opt = {};
opts.push();
opt.option = "";
n = this.options[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 = new 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,username,password,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 = new 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 == 404)
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; ;charset=UTF-8; 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");
//}}}
This document is a ~TiddlyWiki from tiddlyspot.com. A ~TiddlyWiki is an electronic notebook that is great for managing todo lists, personal information, and all sorts of things.
@@font-weight:bold;font-size:1.3em;color:#444; //What now?// @@ Before you can save any changes, you need to enter your password in the form below. Then configure privacy and other site settings at your [[control panel|http://tiddlysquat.tiddlyspot.com/controlpanel]] (your control panel username is //tiddlysquat//).
<<tiddler TspotControls>>
See also GettingStarted.
@@font-weight:bold;font-size:1.3em;color:#444; //Working online// @@ You can edit this ~TiddlyWiki right now, and save your changes using the "save to web" button in the column on the right.
@@font-weight:bold;font-size:1.3em;color:#444; //Working offline// @@ A fully functioning copy of this ~TiddlyWiki can be saved onto your hard drive or USB stick. You can make changes and save them locally without being connected to the Internet. When you're ready to sync up again, just click "upload" and your ~TiddlyWiki will be saved back to tiddlyspot.com.
@@font-weight:bold;font-size:1.3em;color:#444; //Help!// @@ Find out more about ~TiddlyWiki at [[TiddlyWiki.com|http://tiddlywiki.com]]. Also visit [[TiddlyWiki.org|http://tiddlywiki.org]] for documentation on learning and using ~TiddlyWiki. New users are especially welcome on the [[TiddlyWiki mailing list|http://groups.google.com/group/TiddlyWiki]], which is an excellent place to ask questions and get help. If you have a tiddlyspot related problem email [[tiddlyspot support|mailto:support@tiddlyspot.com]].
@@font-weight:bold;font-size:1.3em;color:#444; //Enjoy :)// @@ We hope you like using your tiddlyspot.com site. Please email [[feedback@tiddlyspot.com|mailto:feedback@tiddlyspot.com]] with any comments or suggestions.
{{right{QOTD:}}} <<QOTD Quotations inline>>
{{intro{things that have been completed}}}
{{intro{logged events / notes}}}
{{intro{reference information}}}
{{intro{Stuff added by sww.}}}
<<importTiddlers inline>>
{{intro{things to be done}}}