Welcome to TiddlyWiki created by Jeremy Ruston, Copyright © 2007 UnaMesa Association
Liquid that dissipates instantly upon contact with air. Create DC 25.
Primary damage: fortitude save ~DC15 or fall asleep for 1 round
Secondary damage: fortitude save ~DC15 or sleep another <<roll 1d4>> rounds.
/***
|Name|BetterTimelineMacro|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#BetterTimelineMacro|
|Version|0.5 beta|
|Requires|~TW2.x|
!!!Description:
A replacement for the core timeline macro that offers more features:
*list tiddlers with only specfic tag
*exclude tiddlers with a particular tag
*limit entries to any number of days, for example one week
*specify a start date for the timeline, only tiddlers after that date will be listed.
!!!Installation:
Copy the contents of this tiddler to your TW, tag with systemConfig, save and reload your TW.
Edit the ViewTemplate to add the fullscreen command to the toolbar.
!!!Syntax:
{{{<<timeline better:true>>}}}
''the param better:true enables the advanced features, without it you will get the old timeline behaviour.''
additonal params:
(use only the ones you want)
{{{<<timeline better:true onlyTag:Tag1 excludeTag:Tag2 sortBy:modified/created firstDay:YYYYMMDD maxDays:7 maxEntries:30>>}}}
''explanation of syntax:''
onlyTag: only tiddlers with this tag will be listed. Default is to list all tiddlers.
excludeTag: tiddlers with this tag will not be listed.
sortBy: sort tiddlers by date modified or date created. Possible values are modified or created.
firstDay: useful for starting timeline from a specific date. Example: 20060701 for 1st of July, 2006
maxDays: limits timeline to include only tiddlers from the specified number of days. If you use a value of 7 for example, only tiddlers from the last 7 days will be listed.
maxEntries: limit the total number of entries in the timeline.
!!!History:
*28-07-06: ver 0.5 beta, first release
!!!Code
***/
//{{{
// Return the tiddlers as a sorted array
TiddlyWiki.prototype.getTiddlers = function(field,excludeTag,includeTag)
{
var results = [];
this.forEachTiddler(function(title,tiddler)
{
if(excludeTag == undefined || tiddler.tags.find(excludeTag) == null)
if(includeTag == undefined || tiddler.tags.find(includeTag)!=null)
results.push(tiddler);
});
if(field)
results.sort(function (a,b) {if(a[field] == b[field]) return(0); else return (a[field] < b[field]) ? -1 : +1; });
return results;
}
//this function by Udo
function getParam(params, name, defaultValue)
{
if (!params)
return defaultValue;
var p = params[0][name];
return p ? p[0] : defaultValue;
}
window.old_timeline_handler= config.macros.timeline.handler;
config.macros.timeline.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
var args = paramString.parseParams("list",null,true);
var betterMode = getParam(args, "better", "false");
if (betterMode == 'true')
{
var sortBy = getParam(args,"sortBy","modified");
var excludeTag = getParam(args,"excludeTag",undefined);
var includeTag = getParam(args,"onlyTag",undefined);
var tiddlers = store.getTiddlers(sortBy,excludeTag,includeTag);
var firstDayParam = getParam(args,"firstDay",undefined);
var firstDay = (firstDayParam!=undefined)? firstDayParam: "00010101";
var lastDay = "";
var field= sortBy;
var maxDaysParam = getParam(args,"maxDays",undefined);
var maxDays = (maxDaysParam!=undefined)? maxDaysParam*24*60*60*1000: (new Date()).getTime() ;
var maxEntries = getParam(args,"maxEntries",undefined);
var last = (maxEntries!=undefined) ? tiddlers.length-Math.min(tiddlers.length,parseInt(maxEntries)) : 0;
for(var t=tiddlers.length-1; t>=last; t--)
{
var tiddler = tiddlers[t];
var theDay = tiddler[field].convertToLocalYYYYMMDDHHMM().substr(0,8);
if ((theDay>=firstDay)&& (tiddler[field].getTime()> (new Date()).getTime() - maxDays))
{
if(theDay != lastDay)
{
var theDateList = document.createElement("ul");
place.appendChild(theDateList);
createTiddlyElement(theDateList,"li",null,"listTitle",tiddler[field].formatString(this.dateFormat));
lastDay = theDay;
}
var theDateListItem = createTiddlyElement(theDateList,"li",null,"listLink",null);
theDateListItem.appendChild(createTiddlyLink(place,tiddler.title,true));
}
}
}
else
{
window.old_timeline_handler.apply(this,arguments);
}
}
//}}}
|''Type:''|file|
|''URL:''|http://tiddlywiki.bidix.info/|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
A plain wooden box, containing five scrolls. The writing on the scrolls seems eerily familiar, and the letters apparently change shape while being read.
5 scrolls, containing one of each of:
[[see invisibility|http://www.d20srd.org/srd/spells/seeInvisibility.htm]]
[[magic missile|http://www.d20srd.org/srd/spells/magicMissile.htm]]
[[levitate|http://www.d20srd.org/srd/spells/levitate.htm]]
[[charm person|http://www.d20srd.org/srd/spells/charmPerson.htm]]
[[illusory script|http://www.d20srd.org/srd/spells/illusoryScript.htm]]
Cpt. Holfast runs a pirate operation, waylaying transport airships in the vulnerable skies between France and Britain. He has recently been working closely with [[the Eye|The Eye]], supplying weapons for their fight against [[the Hand|The Hand]] in return for help in distributing and fencing stolen goods.
[[Iosef|Characters/iosef_tesla.html]] [[researches|Iosef's Research]] the [[Philosophers Stone]] and the [[Elixir of Life]].
[[Cassie|Characters/catherine.html]] looks after rumors of airship pirates in the seedy areas of London (Gather Information 24). She learns there are two [[air pirate|Captain Richard Holfast]] [[captains|capt no 2]] terrorizing the skies above Europe. They or their crew have not been seen in London for some time, but when they have new goods to fence, they are brought into the London docks during the night and passed off as legitimate goods from the colonies or the continent.
[[James|Characters/james_norfinwen.html]] goes to the gentleman's club to sniff out sources of income for Iosef. There are two jobs of interest (Gather Information 27): A translating gig - a [[box of ancient scrolls|Box of Ancient Scrolls]] has been found by [[Lord Cavendish]], and he is going apeshit over them - he thinks they lead to treasure. [[Lord Thacker]] reports an infestation of kobolds under his lawns.
James goes to Lord Cavendish, and is promised £100 up front, with £200 more upon completion. When Iosef discovers the scrolls contain spells, he sends James out to find a forger, so he may keep the scrolls for himself.
The first night James attempts this he ends up mugged [Gather Information fumble], but the second night he finds (Gather Information 12) [[Hans|Characters/hans_konig]] at [[The Black Pit]]. Cass is sharing a drink with him - they have been working at the docks together for the last days. James hires Hans (with Cass as Hans' assistant) to make copies of the scrolls, working from Iosef's mansion.
Later the same day, James visits Lord Thacker. After some haggling, they agree upon £30 per kobold killed, with £150 upon proof of the eradication of the vermin. If the infestation is cleared by teatime next day, there is a bonus of £50. Hans and Cass are hired to help in the extermination effort.
Percy is hired as muscle.
Percy gets stuck under a falling stone trap, and very nearly killed by the kobold defenders and left for dead. This blocks the first (cellar) entrance. The rest of the party (sans Iosef) enter the lair through the sewer entrance. After narrowly escaping a few traps, they find the kobold lair proper. In the process they kill 7 kobolds. Being pretty badly chewed up, they decide to regroup, cash in the bounty and find some more firepower. When going back for Percy's corpse, they discover he is, in fact, not dead, but merely unconscious.
James discovers the kobolds are under the protection of a (as yet nameless) crime lord, which has gained considerable support from the kobolds and goblins of the city. He proposes they help [[the Eye|The Eye]] eradicate this threat, thus freeing the city from a group of lowlifes.
A policeman stops by Iosef's town house, asking about a half-ogre that has abandoned his duties in [[the city police|The Police]]. James directs him to the general area of the Filty Pig. He also goes to the Pig and tells [[Sally]] she may give Percy up if she so wishes.
Percy is discovered at the Filthy Pig by 3 policemen. He narowly escapes capture, runs into a tenement building (scaring 3 people in the process), falls down 3 flights of stairs and falls asleep inside a privy behind a pub.
Iosef sends James out after some 'dirt' on the other characters.
James is handed a note which says '9 PM at the docks, pier 7' bu a street urchin (or so it seems). Following up on this lead, he sees a half-orc clumsily trying to blindfold him.
James voluntarily wears his blindfold, and is led through a confusing and thorougly disorienting series of tunnels, stairs and passageways. When the blindfold is removed, he is in a room with three kobold guards and the half orc. There is a bugbear behind a desk, going over some paperwork. James unloads his gun and places it on the desk.
After 5 minutes, when he has gone through the whole stack, he looks up.
"I understand you know some things about the kobolds that are... upsetting the posh ones in their mansions." he says. "What can you tell me?"
James returns "What's it worth to you?" "We'll figure that out later", the bugbear says. "What do you know?is is a give and take situation - you give and i take."
"The kobolds have an unknown backer. He seems to have gathered considerable suport amongst the little people", James says.
The Bugbear furrows his bushy brow. "This new guy has hired these kobolds to burrow to rich peoples homes and rob them. But I believe they are looking for someting very specific - they take other valuables too, of course, but the grapevine says they are looking for something for this unknown master."
"I know something else," James says. "They are reinforcing their traps with magic or very advanced technology that can track and follow one target."
Intrigued, the bugbear says "Very interesting. This is valuable information either way. This needs to be looked into."
"And would it be worth someting to the Eye if these kobolds were eradicated and their operation stopped?" James inquires.
"For now, we are content to let them find what they are looking for - as far as we know, they have not found it yet. But when the time comes for you to attack them again, we will be willing to help with some manpower. The cost of the manpower will be first dibs on whatever loot the kobolds have gathered. The complete shutdown of the kobold operation would be worth £50 (and perhaps a favor) to us - mostly for the annoyance to our rival."
"I shall have to respond to the offer of help later" James responds. "I must consult with my supervisor first - I cannot make this decision. I shall let my contact know what i decide".
After this, James is led through a different set of disorienting, confusing set of tunnels and passageways, and is thrust out into a street in the middle of London
The next day, James looks for the dwarven detective. "Was the information I gave you useful?".
The dwarf replies; "We thought we found him in a seedy pub, but when we turned around he was gone. Why?" James responds "Because I have some more information. My master has hired him for some menial tasks, but if you would like him to fulfill his duties, we can release him to you."
"We have no use for a constable that cannot stay away from the gin. But a sizable contribution to the [[Policemen's Widows Christmas Tree Fund]] might make us ...forget his obligations. About £100 should do the trick." the dwarf grins suggestively.
After consulting with Iosef, James delivers the £100 later that day, thus clearing Percy's slate.
[[The scrolls|Box of Ancient Scrolls]] and a book (on demonology) are stolen from Iosef's study. This prompts Iosef to buy resources for spell scribing so he can learn Arcane Lock and Alarm, using the money from the (now complete) scroll translation scam.
The next day the PCs return to the kobold lair. They have brought a rouge and a fighter goon with them. The rogue quickly discovers the obvious new booby traps the kobolds have placed in the sewer. He also manages to extract a complicated system of lenses and cogwheels from the tracking trap.
A while into the sewers they encounter two kobolds and dispatch them. The dwarf is wounded in his left arm, but after some bandaging continues on. The rogue narrowly escapes a knockback trap (DMG II p 41), which alerts the 3 kobolds and single goblin in the secret corridor after it. Two of the kobolds are killed, and the rest retreat thrugh the secret tunnel, closing the passage behind them. While James and the halfking discuss where the outside trigger might be, the dwarf and Percybegin smashing it open.
The group enter a cave after crawling through the kobold tunnel. There is a old cellar complex about 30ft away from the tunnel entrance. After a short gunfight 2 kobolds and 3 goblins are killed.
Dust booby trap is sprung, which leave James and the dwarf blinded. Three kobolds ambush them. They kill all but one, who manages to escape. Percy pursues, and slams into a door at the end of the hallway.
Percy charges in and shoots the leader. The cartridge is a dud, and creates a cloud of smoke.
The leader dives under desk and shoots from under it. Percy throws the desk away and shotgun-whips the leader while the rest of the group kill the goons.
The leader makes his getaway, but is knocked out cold by Percy. When they open up his escape hatch, the tunnel has been filled.
The room is filled with loot from robberies, all from local prosperous houses, neatly stacked according to type.
When James meets with the lord, a 10% finders fee is agreed upon for the found items, and an independent appraiser is to determine it's value the next day. The total value of the recovered items is judged to be £12000, which makes a £1200 finders fee (less £20 to pay the appraiser).
Iosef goes into the lair to look for magic items later that evening. He finds a small, neatly arranged [[pile of glowing items|Kobold Loot]].
Iosef has James investigate the theft of his scrolls, notes and book. James discovers the sign is the mark of the Crimson Hand, which in London is in deep rivalry with the Eye (both for turf and for reputation), and is led by a man called Ed.
James pursues the marketability of the tracking mechanism stolen from the kobold trap. To this end, he hires a technologist (cost £27) to dismantle the device and create blueprints from it. He then goes to the patent office and files a patent application.
James invests £100 in [[Krupp Waffen]], and mails them a licensing proposal for the tracking device. He also finds pearls for the identify spells (cost £150)
While Hans is singing for his beer, he notices two people (a goblin and a human) sitting at table in the corner. the human seems to be rather afraid of the goblin. When Hans is done singing, he goes closer to the table so he can eavesdrop on the conversation. He overhears the goblin give the human a dressing down: "I will not abide that sort of behavior! If anything of that nature happens again, I'll have your balls for breakfast!". This goes on for some time, until the goblin leaves with "I better see you at the job tonight - and no funny business!". The human, obviously shaken, has a shot to clam his nerves.
Hans takes a good look at the goblin as he leaves, and notices a that he is well fed, his clothes are sturdy and of good quality, if rather plain. He carries a fancy-looking dagger and pistol, and a plain silver ring on his left hand.
Iosef identifies and reads his new magic book, and sends James out to find a herbalist - so he could improve his health by some herbal infusions. James meets Vaden, and although the introduction is rather awkward, the reach an agreement as to Vaden's employment - Vaden is to grow and tend the graden behind Iosef's house. He also identifies the rest of the magic items, taking 4 weeks to do so.
Iosef, wanting to invest, researches [[Krupp Waffen]] more closely.
James gets the dagger evaluated, and it can be sold for £5000 immediately. James's contact agrees to bring James in contact with the buyers. This results in Iosef's finding out that James knows a place to find magic paraphernalia. Iosef then asks James to find some more mind control/illusion spells.
Iosef holds out for another month, trying to bring the price up. He succeeds, and finds a buyer who will give £5800. James meets with the buyer's representative, a rather nondescript man that is often seen around the towns less desireable areas. He seems to be untouchable no matter where he goes.
Iosef reserches the weapons company James has invested in more closely. He fids out it is owned by a half-elven who wants to combine technology and magic to create semi-sentient --soldiers-- menial workers.
Hans tries to find out more about [[the goblin he saw in the pub|Devon Skullheart]]. This inquisitiveness leads to some unwarranted attention. Two goblin goons approach him in a bar
'We 'ear ya been askin' 'bout our boss.' one says. The other follows up 'Yeah, wut's up wiw al' tha curry-us-ity'?. 'Well, your boss is quite the fascinating fellow...' Hans replies -> asks for work, presents himself as the hands-on guy.
Cassie looks for information on [[the pirate captain that killed her father|Captain Richard Holfast]], and discovers he has a weapons drop planned around november 20th.
James asks [[the Immortal|The Immortal]] to look for books on blood bonding.
Iosef [[makes some progress in his research|Iosef's Research]].
!!November 5th
[[Devon Skullheart]] approaches Hans. 'Ah 'ear ya been lookin' fer some work. Mah employers can cert'nly use a man of yer talents. Ah've got a small, reltivly easy job ta test ye out wiw. 'Tis a straight B&E, minimal security, but a few righ' tricky locks. We start t'morrow nigh', if yer up to it' he says. 'That's fair enough. I'll be ready' Hans replies.
Iosef receives a letter from [[Krupp Waffen]]. They are very interested in licensing the [[Kobold Tracking Mechanism]], and are offering:
* £20.000 up front, first rights on two [[mechanical workers]], and 1% of revenue annualy
* £7.000 up front and 3% of annual revenue
Iosef counters with £1.000 up front, first rights on one finished product and %3 annual revenue. He also expresses his interest in a face-to-face meeting to discuss the finer points of the agreement.
James goes to [[the Black Pit|The Black Pit]] to talk to Hans and Cass: 'Me master, he wishes ta hire the two a'yous permanent-like, wi' a [[contract|Iosef's Employment Contract]] an' all. Don' worry, ye'll be paid well - he'll even put ya up!' he says, after placing three pints of beer on the table. 'I have already sought employment elsewhere..' Hans says. 'Oh? with whom?' James asks. 'Eh... with the Eye' Hans replies evasively. 'Is this a problem?'. 'Well, my master will expect you to be available at short notice. He would prefer that you did not have multiple masters, as it were.' James says. 'Well, i'd rather not commit to anything right now' Hans says. 'I'll get back ta you,, allright? 'Sure thing, whatever ya like man,' James replies.
'I will take a contract though - gainful employment does appeal to me.' Cassie says. 'Jolly! Be at me master's estate at 5 tomorrow, an' we'll sign us a contract!' James says.
Iosef wants to prevent Hans being employed by the Eye. James goes to see [[Sally]] later that night, after snooping around a bit to find out that it was [[Devon Skullheart]] Hans had been talking with.
'Good e'enin', ma'am! I've favor to ask of ye - a ..friend.. of mine has sought employment within the Eye strtin' tomorrow, and I'd like that not to happen. 'Might be possible. Who is he, and who's he been talkin' to?' ' A young man, goes by the name Hans. He's been talkin' to a Glancer named Skullheart.' 'Oh, old Dev. The greedy bastard won't even think twice if he's handed say, £30-40 - anonymously of course - to not hire the young man. If you got 40 quid, i'll take care of it for ya.' Sally replies.
!!November 6th
Hans has his test run scheduled with the Eye. Early in the afternoon a goblin stops by and informs him that 'Mr. Skullhert shan't be needing yer services'.
Hans and Cassie sign their contracts, and are shown to their rooms.
James pumps Hans and Cassie for info on the Eye and the Hand.
James talks to [[Sally]] about [[the turf war|The Dock Wars]], and asks if they might be of assistance to the Eye.
!!November 8th
James receives a note with his morning newspaper:
>Tonight
The following evening James makes his way to the docks.
'ello.' Grusnakh says, dangling a black silk handkerchief. 'Ya know the drill.'
'Yeah...yeah', James replies, tying the handkerchief around his eyes.
He is again led through a utterly confusing series of twists and turns, and ends up in Morgar's office (which has moved since last time) [[Morgar|Morgar Clobberton]] sits behind his desk, paperwork neatly arranged in tidy piles on top of it. A comfortable chair is placed strategically in front of it.
James unchambers his gun and places it and the bullets on the desk, then moves next to the chair. Morgar indicates James may sit, and states, 'Well. You wished to see me - something about assisting us in our battles with the Hand. Your benefit to us as unmanaged assets is obvious, but did you have anyting particular in mind?' 'I was thinking along the lines of information gathering and infiltration' James replies. 'We do have our own - quite capable - agents and spies, but thank you for your kind offer' 'Ah - but a new recruit to the Hand might get a feel for the mood in the organization - sniff out some rumors and the like, maybe verify what your venerable agents are reporting?'
Smiling, Morgar says 'Well, what an amazing willingness to please. Why the sudden interest in striking at the Hand, if I might so inquire?' 'Suffice it to say that common foes make timely allies,' James replies. 'If you want something to do that bad, we have reports that The Hand have a [[smallish weapons hoard down on pier 19|Weapon Stash]] we'd not like to see the Hand use.
'We could, of course, just blow it up ourselves, but that would be crude and ungentlemanly. Plus, it would give us a fair assessment of your abilities if you were to take on the assignment.'
!!November 9th
Cass is sent to scope out the weapons stash over the next few days - takes menial work at the docks close to the stash. Over the next two days she notices that
* the number of workers is disproportionate to the apparent work
* quite a few of the 'workers' move like fighters, not laborers
* there are some with handguns
* apparent lookouts
* a couple half-ogres/dwarves - more that would be expected
Hans is sent into town for ragged, beggarly clothing. He pays a beggar in an alley one shilling for his clothing.
!!November 11th
Cassie gives her report.
James is sent undercover as a beggar for the next ten days, with instructions to note the movements of the guards in detail. He spends over six-and-a-half hours on his disguise, making sure not a hair is out of place.
Over the 10 days James finds:
* Three ogres - one on guard at any given time
* Two dwarven handlers per ogre
* 5 humans patrolling
In staggered shifts - seemingly chaotic at first, but a pattern emerges.
james returns to Iosef, and they start planning a daring heist to get the ammo for themselves
!!November 20th
[[Captain Holfast|Captain Richard Holfast]] has a weapons drop for the eye scheduled
!November 21st
Cassie hears rumors that her pirate captain nemesis has been spotted in Edinburg.
!November 22
!!Planning the heist
Iosef sends James out for some high-grade [[sleeping gas|Alchemical Sleeping Gas]] and poison - both [[gas|Wicked Poison Gas]] (delivered by a 15ft radius grenade), and to [[coat bolts|Really Wicked Poison]], along with gas masks for the team. James also acquires 2 [[repeating crossbows|Repeating Crossbow]] with 50 bolts each for £100, and rents a large wagon (with driver)
!!November 24
The armaments arrive during the night. Hans spends the following day applying poison to 20 crossbow bolts, so he and James have 10 poisoned darts each.
After nightfall Hans, Percy and James take their rented wagon close to [[the Hand's weapon stash|Weapon Stash]]. Percy waits by the wagon, with instructions to come charging when he can hear action.
James and Hans sneak up to the board fence surounding the two warehouses, and quickly climb over the fence. Hans hides behind the corner of the large warehouse, and quickly takes out the patrolling guard with a poison bolt. James swings a padded grappling hook up on the roof of the large warehouse and quickly climbs up the knotted rope.
Once on the rooftop, James drops prone, waiting for the closest guard to approach. the guard is quickly dispatched, but the sound of the collapsing body alerts the second patrolling human.
'Oi! Ya awlri't up thar?' he asks, walking over.
Not wanting to blow his gover, james remains completely silent.
'Sammy! Whut's goin' on up thar?' the guard asks again.
In his very best embarrased, drunken voice, James replies "Ah ..hic.. fell.."
'Bloddy hell Sammy, ye're drunk again!' the guard says, returning to his rounds.
'Who'ye takin' tae?' a gruff voice asks.
'That damn fool Sammy. He's brought a bootle to the job again - been fallin' all over the roof.' the guard replies
Praising his lucky stars that he was not discovered, James slowly creeps along the roof, and quickly takes out the second rooftop lookout. soon after this is accomplished, James and Hans hear the warehouse doors opening. 'Is thar sommat goin' on? ah coulda swore thar were some noise on tha roof.' a human voice says. 'Nah, that's jest Sam - the fool's drunk again. Cannae stey oan 'is feet,' the dwarf replies. This seems to satisfy the human, because the door is closed again.
James jumps across the gap between the two buildings, landing silently. The lookout is quickly killed, but attracts the attention of the guard inside the warehouse. The warehouse door pens,
'Any of ye been 'earing things tonight? I'm damn well sure there were summat on tha roof?' a human voice inquires.
The patrolling guard replies, 'well, sammy's been drinkin again - he can't seem to keep his feet steady.. bu he en't on your roof.'
'Ah'll go check then.' James hears as the door closes.
/***
|Name:|CloseOnCancelPlugin|
|Description:|Closes the tiddler if you click new tiddler then cancel. Default behaviour is to leave it open|
|Version:|3.0.1 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 2008) $|
|Source:|http://mptw.tiddlyspot.com/#CloseOnCancelPlugin|
|Author:|Simon Baird <simon.baird@gmail.com>|
|License:|http://mptw.tiddlyspot.com/#TheBSDLicense|
***/
//{{{
merge(config.commands.cancelTiddler,{
handler_mptw_orig_closeUnsaved: config.commands.cancelTiddler.handler,
handler: function(event,src,title) {
this.handler_mptw_orig_closeUnsaved(event,src,title);
if (!store.tiddlerExists(title) && !store.isShadowTiddler(title))
story.closeTiddler(title,true);
return false;
}
});
//}}}
/***
|Name|CollapseTiddlersPlugin|
|Source|http://gensoft.revhost.net/Collapse.html|
|Version|2008.03.06|
|Author|Bradley Meck (modified by ELS)|
|License|unknown|
|~CoreVersion|2.1|
|Type|plugin|
|Requires|CollapsedTemplate|
|Overrides||
|Description|show/hide content of a tiddler while leaving tiddler title visible|
|ELS 3/6/2008: refactored code for size reduction, readability, and I18N/L10N-readiness. Also added 'folded' flag to tiddler elements (for use by other plugins that need to know if tiddler is folded (e.g., [[SinglePageModePlugin]]) |
|ELS 10/11/2007: moved [[FoldFirst]] inline script and converted to {{{<<foldFirst>>}}} macro. |
|ELS 9/12/2007: suspend/resume SinglePageMode (SPM/TPM/BPM) when folding/unfolding tiddlers |
|ELS 6/5/2007: add "return false" at the end of each command handler to prevent IE 'page transition' problem. |
|ELS 3/30/2007: add a shadow definition for CollapsedTemplate. Tweak ViewTemplate shadow so "fold/unfold" and "focus" toolbar items automatically appear when using default templates. Remove error check for "CollapsedTemplate" existence, since shadow version will now always work as a fallback. |
|ELS 2/24/2006: added fallback to "CollapsedTemplate" if "WebCollapsedTemplate" is not found |
|ELS 2/6/2006: added check for 'readOnly' flag to use alternative "WebCollapsedTemplate" |
***/
//{{{
config.shadowTiddlers.CollapsedTemplate=
"<!--{{{-->\
<div class='toolbar' macro='toolbar expandTiddler collapseOthers closeTiddler closeOthers +editTiddler permalink references jump'></div>\
<div class='title' macro='view title'></div>\
<!--}}}-->";
// automatically tweak shadow ViewTemplate to add "collapseTiddler collapseOthers" commands
config.shadowTiddlers.ViewTemplate=config.shadowTiddlers.ViewTemplate.replace(/closeTiddler/,"collapseTiddler collapseOthers closeTiddler");
config.commands.collapseTiddler = {
text: "fold",
tooltip: "Collapse this tiddler",
collapsedTemplate: "CollapsedTemplate",
webCollapsedTemplate: "WebCollapsedTemplate",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
// don't fold tiddlers that are being edited!
if(story.isDirty(e.getAttribute("tiddler"))) return false;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(e);
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","true");
return false;
},
getCollapsedTemplate: function() {
if (readOnly&&store.tiddlerExists(this.webCollapsedTemplate))
return this.webCollapsedTemplate;
else
return this.collapsedTemplate
},
saveTemplate: function(e) {
if (e.getAttribute("savedTemplate")==undefined)
e.setAttribute("savedTemplate",e.getAttribute("template"));
},
// fold/unfold tiddler with suspend/resume of single/top/bottom-of-page mode
display: function(title,t) {
var opt=config.options;
var saveSPM=opt.chkSinglePageMode; opt.chkSinglePageMode=false;
var saveTPM=opt.chkTopOfPageMode; opt.chkTopOfPageMode=false;
var saveBPM=opt.chkBottomOfPageMode; opt.chkBottomOfPageMode=false;
story.displayTiddler(null,title,t);
opt.chkBottomOfPageMode=saveBPM;
opt.chkTopOfPageMode=saveTPM;
opt.chkSinglePageMode=saveSPM;
}
}
config.commands.expandTiddler = {
text: "unfold",
tooltip: "Expand this tiddler",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
var t = e.getAttribute("savedTemplate");
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","false");
return false;
}
}
config.macros.collapseAll = {
text: "collapse all",
tooltip: "Collapse all tiddlers",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
createTiddlyButton(place,this.text,this.tooltip,function(){
story.forEachTiddler(function(title,tiddler){
if(story.isDirty(title)) return;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(tiddler);
config.commands.collapseTiddler.display(title,t);
tiddler.folded=true;
})
})
}
}
config.macros.expandAll = {
text: "expand all",
tooltip: "Expand all tiddlers",
handler: function(place,macroName,params,wikifier,paramString,tiddler){
createTiddlyButton(place,this.text,this.tooltip,function(){
story.forEachTiddler(function(title,tiddler){
var t=config.commands.collapseTiddler.getCollapsedTemplate();
if(tiddler.getAttribute("template")!=t) return; // re-display only if collapsed
var t=tiddler.getAttribute("savedTemplate");
config.commands.collapseTiddler.display(title,t);
tiddler.folded=false;
})
})
}
}
config.commands.collapseOthers = {
text: "focus",
tooltip: "Expand this tiddler and collapse all others",
handler: function(event,src,title) {
var e = story.findContainingTiddler(src); if (!e) return false;
story.forEachTiddler(function(title,tiddler) {
if(story.isDirty(title)) return;
var t=config.commands.collapseTiddler.getCollapsedTemplate();
if (e==tiddler) t=e.getAttribute("savedTemplate");
config.commands.collapseTiddler.saveTemplate(tiddler);
config.commands.collapseTiddler.display(title,t);
tiddler.folded=(e!=tiddler);
})
return false;
}
}
// {{{<<foldFirst>>}}} macro forces tiddler to be folded when *initially* displayed.
// Subsequent re-render does NOT re-fold tiddler, but closing/re-opening tiddler DOES cause it to fold first again.
config.macros.foldFirst = {
handler: function(place,macroName,params,wikifier,paramString,tiddler){
var e=story.findContainingTiddler(place);
if (e.getAttribute("foldedFirst")=="true") return; // already been folded once
var title=e.getAttribute("tiddler")
var t=config.commands.collapseTiddler.getCollapsedTemplate();
config.commands.collapseTiddler.saveTemplate(e);
config.commands.collapseTiddler.display(title,t);
e.setAttribute("folded","true");
e.setAttribute("foldedFirst","true"); // only when tiddler is first rendered
return false;
}
}
//}}}
Type the text for 'New Tiddler'
config.options.txtTheme = "NPLLTheme";
/***
|''Name:''|DataTiddlerPlugin|
|''Version:''|1.0.6 (2006-08-26)|
|''Source:''|http://tiddlywiki.abego-software.de/#DataTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|
!Description
Enhance your tiddlers with structured data (such as strings, booleans, numbers, or even arrays and compound objects) that can be easily accessed and modified through named fields (in JavaScript code).
Such tiddler data can be used in various applications. E.g. you may create tables that collect data from various tiddlers.
''//Example: "Table with all December Expenses"//''
{{{
<<forEachTiddler
where
'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'
write
'"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\n"'
>>
}}}
//(This assumes that expenses are stored in tiddlers tagged with "expense".)//
<<forEachTiddler
where
'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'
write
'"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\n"'
>>
For other examples see DataTiddlerExamples.
''Access and Modify Tiddler Data''
You can "attach" data to every tiddler by assigning a JavaScript value (such as a string, boolean, number, or even arrays and compound objects) to named fields.
These values can be accessed and modified through the following Tiddler methods:
|!Method|!Example|!Description|
|{{{data(field)}}}|{{{t.data("age")}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined {{{undefined}}} is returned.|
|{{{data(field,defaultValue)}}}|{{{t.data("isVIP",false)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined the defaultValue is returned.|
|{{{data()}}}|{{{t.data()}}}|Returns the data object of the tiddler, with a property for every field. The properties of the returned data object may only be read and not be modified. To modify the data use DataTiddler.setData(...) or the corresponding Tiddler method.|
|{{{setData(field,value)}}}|{{{t.setData("age",42)}}}|Sets the value of the given data field of the tiddler to the value. When the value is {{{undefined}}} the field is removed.|
|{{{setData(field,value,defaultValue)}}}|{{{t.setData("isVIP",flag,false)}}}|Sets the value of the given data field of the tiddler to the value. When the value is equal to the defaultValue no value is set (and the field is removed).|
Alternatively you may use the following functions to access and modify the data. In this case the tiddler argument is either a tiddler or the name of a tiddler.
|!Method|!Description|
|{{{DataTiddler.getData(tiddler,field)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined {{{undefined}}} is returned.|
|{{{DataTiddler.getData(tiddler,field,defaultValue)}}}|Returns the value of the given data field of the tiddler. When no such field is defined or its value is undefined the defaultValue is returned.|
|{{{DataTiddler.getDataObject(tiddler)}}}|Returns the data object of the tiddler, with a property for every field. The properties of the returned data object may only be read and not be modified. To modify the data use DataTiddler.setData(...) or the corresponding Tiddler method.|
|{{{DataTiddler.setData(tiddler,field,value)}}}|Sets the value of the given data field of the tiddler to the value. When the value is {{{undefined}}} the field is removed.|
|{{{DataTiddler.setData(tiddler,field,value,defaultValue)}}}|Sets the value of the given data field of the tiddler to the value. When the value is equal to the defaultValue no value is set (and the field is removed).|
//(For details on the various functions see the detailed comments in the source code.)//
''Data Representation in a Tiddler''
The data of a tiddler is stored as plain text in the tiddler's content/text, inside a "data" section that is framed by a {{{<data>...</data>}}} block. Inside the data section the information is stored in the [[JSON format|http://www.crockford.com/JSON/index.html]].
//''Data Section Example:''//
{{{
<data>{"isVIP":true,"user":"John Brown","age":34}</data>
}}}
The data section is not displayed when viewing the tiddler (see also "The showData Macro").
Beside the data section a tiddler may have all kind of other content.
Typically you will not access the data section text directly but use the methods given above. Nevertheless you may retrieve the text of the data section's content through the {{{DataTiddler.getDataText(tiddler)}}} function.
''Saving Changes''
The "setData" methods respect the "ForceMinorUpdate" and "AutoSave" configuration values. I.e. when "ForceMinorUpdate" is true changing a value using setData will not affect the "modifier" and "modified" attributes. With "AutoSave" set to true every setData will directly save the changes after a setData.
''Notifications''
No notifications are sent when a tiddler's data value is changed through the "setData" methods.
''Escape Data Section''
In case that you want to use the text {{{<data>}}} or {{{</data>}}} in a tiddler text you must prefix the text with a tilde ('~'). Otherwise it may be wrongly considered as the data section. The tiddler text {{{~<data>}}} is displayed as {{{<data>}}}.
''The showData Macro''
By default the data of a tiddler (that is stored in the {{{<data>...</data>}}} section of the tiddler) is not displayed. If you want to display this data you may used the {{{<<showData ...>>}}} macro:
''Syntax:''
|>|{{{<<}}}''showData '' [''JSON''] [//tiddlerName//] {{{>>}}}|
|''JSON''|By default the data is rendered as a table with a "Name" and "Value" column. When defining ''JSON'' the data is rendered in JSON format|
|//tiddlerName//|Defines the tiddler holding the data to be displayed. When no tiddler is given the tiddler containing the showData macro is used. When the tiddler name contains spaces you must quote the name (or use the {{{[[...]]}}} syntax.)|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
!Revision history
* v1.0.6 (2006-08-26)
** Removed misleading comment
* v1.0.5 (2006-02-27) (Internal Release Only)
** Internal
*** Make "JSLint" conform
* v1.0.4 (2006-02-05)
** Bugfix: showData fails in TiddlyWiki 2.0
* v1.0.3 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.2 (2005-12-22)
** Enhancements:
*** Handle texts "<data>" or "</data>" more robust when used in a tiddler text or as a field value.
*** Improved (JSON) error messages.
** Bugs fixed:
*** References are not updated when using the DataTiddler.
*** Changes to compound objects are not always saved.
*** "~</data>" is not rendered correctly (expected "</data>")
* v1.0.1 (2005-12-13)
** Features:
*** The showData macro supports an optional "tiddlername" argument to specify the tiddler containing the data to be displayed
** Bugs fixed:
*** A script immediately following a data section is deleted when the data is changed. (Thanks to GeoffS for reporting.)
* v1.0.0 (2005-12-12)
** initial version
!Code
***/
//{{{
//============================================================================
//============================================================================
// DataTiddlerPlugin
//============================================================================
//============================================================================
// Ensure that the DataTiddler Plugin is only installed once.
//
if (!version.extensions.DataTiddlerPlugin) {
version.extensions.DataTiddlerPlugin = {
major: 1, minor: 0, revision: 6,
date: new Date(2006, 7, 26),
type: 'plugin',
source: "http://tiddlywiki.abego-software.de/#DataTiddlerPlugin"
};
// For backward compatibility with v1.2.x
//
if (!window.story) window.story=window;
if (!TiddlyWiki.prototype.getTiddler) {
TiddlyWiki.prototype.getTiddler = function(title) {
var t = this.tiddlers[title];
return (t !== undefined && t instanceof Tiddler) ? t : null;
};
}
//============================================================================
// DataTiddler Class
//============================================================================
// ---------------------------------------------------------------------------
// Configurations and constants
// ---------------------------------------------------------------------------
function DataTiddler() {
}
DataTiddler = {
// Function to stringify a JavaScript value, producing the text for the data section content.
// (Must match the implementation of DataTiddler.parse.)
//
stringify : null,
// Function to parse the text for the data section content, producing a JavaScript value.
// (Must match the implementation of DataTiddler.stringify.)
//
parse : null
};
// Ensure access for IE
window.DataTiddler = DataTiddler;
// ---------------------------------------------------------------------------
// Data Accessor and Mutator
// ---------------------------------------------------------------------------
// Returns the value of the given data field of the tiddler.
// When no such field is defined or its value is undefined
// the defaultValue is returned.
//
// @param tiddler either a tiddler name or a tiddler
//
DataTiddler.getData = function(tiddler, field, defaultValue) {
var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
if (!(t instanceof Tiddler)) {
throw "Tiddler expected. Got "+tiddler;
}
return DataTiddler.getTiddlerDataValue(t, field, defaultValue);
};
// Sets the value of the given data field of the tiddler to
// the value. When the value is equal to the defaultValue
// no value is set (and the field is removed)
//
// Changing data of a tiddler will not trigger notifications.
//
// @param tiddler either a tiddler name or a tiddler
//
DataTiddler.setData = function(tiddler, field, value, defaultValue) {
var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
if (!(t instanceof Tiddler)) {
throw "Tiddler expected. Got "+tiddler+ "("+t+")";
}
DataTiddler.setTiddlerDataValue(t, field, value, defaultValue);
};
// Returns the data object of the tiddler, with a property for every field.
//
// The properties of the returned data object may only be read and
// not be modified. To modify the data use DataTiddler.setData(...)
// or the corresponding Tiddler method.
//
// If no data section is defined a new (empty) object is returned.
//
// @param tiddler either a tiddler name or a Tiddler
//
DataTiddler.getDataObject = function(tiddler) {
var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
if (!(t instanceof Tiddler)) {
throw "Tiddler expected. Got "+tiddler;
}
return DataTiddler.getTiddlerDataObject(t);
};
// Returns the text of the content of the data section of the tiddler.
//
// When no data section is defined for the tiddler null is returned
//
// @param tiddler either a tiddler name or a Tiddler
// @return [may be null]
//
DataTiddler.getDataText = function(tiddler) {
var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;
if (!(t instanceof Tiddler)) {
throw "Tiddler expected. Got "+tiddler;
}
return DataTiddler.readDataSectionText(t);
};
// ---------------------------------------------------------------------------
// Internal helper methods (must not be used by code from outside this plugin)
// ---------------------------------------------------------------------------
// Internal.
//
// The original JSONError is not very user friendly,
// especially it does not define a toString() method
// Therefore we extend it here.
//
DataTiddler.extendJSONError = function(ex) {
if (ex.name == 'JSONError') {
ex.toString = function() {
return ex.name + ": "+ex.message+" ("+ex.text+")";
};
}
return ex;
};
// Internal.
//
// @param t a Tiddler
//
DataTiddler.getTiddlerDataObject = function(t) {
if (t.dataObject === undefined) {
var data = DataTiddler.readData(t);
t.dataObject = (data) ? data : {};
}
return t.dataObject;
};
// Internal.
//
// @param tiddler a Tiddler
//
DataTiddler.getTiddlerDataValue = function(tiddler, field, defaultValue) {
var value = DataTiddler.getTiddlerDataObject(tiddler)[field];
return (value === undefined) ? defaultValue : value;
};
// Internal.
//
// @param tiddler a Tiddler
//
DataTiddler.setTiddlerDataValue = function(tiddler, field, value, defaultValue) {
var data = DataTiddler.getTiddlerDataObject(tiddler);
var oldValue = data[field];
if (value == defaultValue) {
if (oldValue !== undefined) {
delete data[field];
DataTiddler.save(tiddler);
}
return;
}
data[field] = value;
DataTiddler.save(tiddler);
};
// Internal.
//
// Reads the data section from the tiddler's content and returns its text
// (as a String).
//
// Returns null when no data is defined.
//
// @param tiddler a Tiddler
// @return [may be null]
//
DataTiddler.readDataSectionText = function(tiddler) {
var matches = DataTiddler.getDataTiddlerMatches(tiddler);
if (matches === null || !matches[2]) {
return null;
}
return matches[2];
};
// Internal.
//
// Reads the data section from the tiddler's content and returns it
// (as an internalized object).
//
// Returns null when no data is defined.
//
// @param tiddler a Tiddler
// @return [may be null]
//
DataTiddler.readData = function(tiddler) {
var text = DataTiddler.readDataSectionText(tiddler);
try {
return text ? DataTiddler.parse(text) : null;
} catch(ex) {
throw DataTiddler.extendJSONError(ex);
}
};
// Internal.
//
// Returns the serialized text of the data of the given tiddler, as it
// should be stored in the data section.
//
// @param tiddler a Tiddler
//
DataTiddler.getDataTextOfTiddler = function(tiddler) {
var data = DataTiddler.getTiddlerDataObject(tiddler);
return DataTiddler.stringify(data);
};
// Internal.
//
DataTiddler.indexOfNonEscapedText = function(s, subString, startIndex) {
var index = s.indexOf(subString, startIndex);
while ((index > 0) && (s[index-1] == '~')) {
index = s.indexOf(subString, index+1);
}
return index;
};
// Internal.
//
DataTiddler.getDataSectionInfo = function(text) {
// Special care must be taken to handle "<data>" and "</data>" texts inside
// a data section.
// Also take care not to use an escaped <data> (i.e. "~<data>") as the start
// of a data section. (Same for </data>)
// NOTE: we are explicitly searching for a data section that contains a JSON
// string, i.e. framed with braces. This way we are little bit more robust in
// case the tiddler contains unescaped texts "<data>" or "</data>". This must
// be changed when using a different stringifier.
var startTagText = "<data>{";
var endTagText = "}</data>";
var startPos = 0;
// Find the first not escaped "<data>".
var startDataTagIndex = DataTiddler.indexOfNonEscapedText(text, startTagText, 0);
if (startDataTagIndex < 0) {
return null;
}
// Find the *last* not escaped "</data>".
var endDataTagIndex = text.indexOf(endTagText, startDataTagIndex);
if (endDataTagIndex < 0) {
return null;
}
var nextEndDataTagIndex;
while ((nextEndDataTagIndex = text.indexOf(endTagText, endDataTagIndex+1)) >= 0) {
endDataTagIndex = nextEndDataTagIndex;
}
return {
prefixEnd: startDataTagIndex,
dataStart: startDataTagIndex+(startTagText.length)-1,
dataEnd: endDataTagIndex,
suffixStart: endDataTagIndex+(endTagText.length)
};
};
// Internal.
//
// Returns the "matches" of a content of a DataTiddler on the
// "data" regular expression. Return null when no data is defined
// in the tiddler content.
//
// Group 1: text before data section (prefix)
// Group 2: content of data section
// Group 3: text behind data section (suffix)
//
// @param tiddler a Tiddler
// @return [may be null] null when the tiddler contains no data section, otherwise see above.
//
DataTiddler.getDataTiddlerMatches = function(tiddler) {
var text = tiddler.text;
var info = DataTiddler.getDataSectionInfo(text);
if (!info) {
return null;
}
var prefix = text.substr(0,info.prefixEnd);
var data = text.substr(info.dataStart, info.dataEnd-info.dataStart+1);
var suffix = text.substr(info.suffixStart);
return [text, prefix, data, suffix];
};
// Internal.
//
// Saves the data in a <data> block of the given tiddler (as a minor change).
//
// The "chkAutoSave" and "chkForceMinorUpdate" options are respected.
// I.e. the TiddlyWiki *file* is only saved when AutoSave is on.
//
// Notifications are not send.
//
// This method should only be called when the data really has changed.
//
// @param tiddler
// the tiddler to be saved.
//
DataTiddler.save = function(tiddler) {
var matches = DataTiddler.getDataTiddlerMatches(tiddler);
var prefix;
var suffix;
if (matches === null) {
prefix = tiddler.text;
suffix = "";
} else {
prefix = matches[1];
suffix = matches[3];
}
var dataText = DataTiddler.getDataTextOfTiddler(tiddler);
var newText =
(dataText !== null)
? prefix + "<data>" + dataText + "</data>" + suffix
: prefix + suffix;
if (newText != tiddler.text) {
// make the change in the tiddlers text
// ... see DataTiddler.MyTiddlerChangedFunction
tiddler.isDataTiddlerChange = true;
// ... do the action change
tiddler.set(
tiddler.title,
newText,
config.options.txtUserName,
config.options.chkForceMinorUpdate? undefined : new Date(),
tiddler.tags);
// ... see DataTiddler.MyTiddlerChangedFunction
delete tiddler.isDataTiddlerChange;
// Mark the store as dirty.
store.dirty = true;
// AutoSave if option is selected
if(config.options.chkAutoSave) {
saveChanges();
}
}
};
// Internal.
//
DataTiddler.MyTiddlerChangedFunction = function() {
// Remove the data object from the tiddler when the tiddler is changed
// by code other than DataTiddler code.
//
// This is necessary since the data object is just a "cached version"
// of the data defined in the data section of the tiddler and the
// "external" change may have changed the content of the data section.
// Thus we are not sure if the data object reflects the data section
// contents.
//
// By deleting the data object we ensure that the data object is
// reconstructed the next time it is needed, with the data defined by
// the data section in the tiddler's text.
// To indicate that a change is a "DataTiddler change" a temporary
// property "isDataTiddlerChange" is added to the tiddler.
if (this.dataObject && !this.isDataTiddlerChange) {
delete this.dataObject;
}
// call the original code.
DataTiddler.originalTiddlerChangedFunction.apply(this, arguments);
};
//============================================================================
// Formatters
//============================================================================
// This formatter ensures that "~<data>" is rendered as "<data>". This is used to
// escape the "<data>" of a data section, just in case someone really wants to use
// "<data>" as a text in a tiddler and not start a data section.
//
// Same for </data>.
//
config.formatters.push( {
name: "data-escape",
match: "~<\\/?data>",
handler: function(w) {
w.outputText(w.output,w.matchStart + 1,w.nextMatch);
}
} );
// This formatter ensures that <data>...</data> sections are not rendered.
//
config.formatters.push( {
name: "data",
match: "<data>",
handler: function(w) {
var info = DataTiddler.getDataSectionInfo(w.source);
if (info && info.prefixEnd == w.matchStart) {
w.nextMatch = info.suffixStart;
} else {
w.outputText(w.output,w.matchStart,w.nextMatch);
}
}
} );
//============================================================================
// Tiddler Class Extension
//============================================================================
// "Hijack" the changed method ---------------------------------------------------
DataTiddler.originalTiddlerChangedFunction = Tiddler.prototype.changed;
Tiddler.prototype.changed = DataTiddler.MyTiddlerChangedFunction;
// Define accessor methods -------------------------------------------------------
// Returns the value of the given data field of the tiddler. When no such field
// is defined or its value is undefined the defaultValue is returned.
//
// When field is undefined (or null) the data object is returned. (See
// DataTiddler.getDataObject.)
//
// @param field [may be null, undefined]
// @param defaultValue [may be null, undefined]
// @return [may be null, undefined]
//
Tiddler.prototype.data = function(field, defaultValue) {
return (field)
? DataTiddler.getTiddlerDataValue(this, field, defaultValue)
: DataTiddler.getTiddlerDataObject(this);
};
// Sets the value of the given data field of the tiddler to the value. When the
// value is equal to the defaultValue no value is set (and the field is removed).
//
// @param value [may be null, undefined]
// @param defaultValue [may be null, undefined]
//
Tiddler.prototype.setData = function(field, value, defaultValue) {
DataTiddler.setTiddlerDataValue(this, field, value, defaultValue);
};
//============================================================================
// showData Macro
//============================================================================
config.macros.showData = {
// Standard Properties
label: "showData",
prompt: "Display the values stored in the data section of the tiddler"
};
config.macros.showData.handler = function(place,macroName,params) {
// --- Parsing ------------------------------------------
var i = 0; // index running over the params
// Parse the optional "JSON"
var showInJSONFormat = false;
if ((i < params.length) && params[i] == "JSON") {
i++;
showInJSONFormat = true;
}
var tiddlerName = story.findContainingTiddler(place).id.substr(7);
if (i < params.length) {
tiddlerName = params[i];
i++;
}
// --- Processing ------------------------------------------
try {
if (showInJSONFormat) {
this.renderDataInJSONFormat(place, tiddlerName);
} else {
this.renderDataAsTable(place, tiddlerName);
}
} catch (e) {
this.createErrorElement(place, e);
}
};
config.macros.showData.renderDataInJSONFormat = function(place,tiddlerName) {
var text = DataTiddler.getDataText(tiddlerName);
if (text) {
createTiddlyElement(place,"pre",null,null,text);
}
};
config.macros.showData.renderDataAsTable = function(place,tiddlerName) {
var text = "|!Name|!Value|\n";
var data = DataTiddler.getDataObject(tiddlerName);
if (data) {
for (var i in data) {
var value = data[i];
text += "|"+i+"|"+DataTiddler.stringify(value)+"|\n";
}
}
wikify(text, place);
};
// Internal.
//
// Creates an element that holds an error message
//
config.macros.showData.createErrorElement = function(place, exception) {
var message = (exception.description) ? exception.description : exception.toString();
return createTiddlyElement(place,"span",null,"showDataError","<<showData ...>>: "+message);
};
// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
".showDataError{color: #ffffff;background-color: #880000;}",
"showData");
} // of "install only once"
// Used Globals (for JSLint) ==============
// ... TiddlyWiki Core
/*global createTiddlyElement, saveChanges, store, story, wikify */
// ... DataTiddler
/*global DataTiddler */
// ... JSON
/*global JSON */
/***
!JSON Code, used to serialize the data
***/
/*
Copyright (c) 2005 JSON.org
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, sublicense, 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 Software shall be used for Good, not Evil.
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. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
The global object JSON contains two methods.
JSON.stringify(value) takes a JavaScript value and produces a JSON text.
The value must not be cyclical.
JSON.parse(text) takes a JSON text and produces a JavaScript value. It will
throw a 'JSONError' exception if there is an error.
*/
var JSON = {
copyright: '(c)2005 JSON.org',
license: 'http://www.crockford.com/JSON/license.html',
/*
Stringify a JavaScript value, producing a JSON text.
*/
stringify: function (v) {
var a = [];
/*
Emit a string.
*/
function e(s) {
a[a.length] = s;
}
/*
Convert a value.
*/
function g(x) {
var c, i, l, v;
switch (typeof x) {
case 'object':
if (x) {
if (x instanceof Array) {
e('[');
l = a.length;
for (i = 0; i < x.length; i += 1) {
v = x[i];
if (typeof v != 'undefined' &&
typeof v != 'function') {
if (l < a.length) {
e(',');
}
g(v);
}
}
e(']');
return;
} else if (typeof x.toString != 'undefined') {
e('{');
l = a.length;
for (i in x) {
v = x[i];
if (x.hasOwnProperty(i) &&
typeof v != 'undefined' &&
typeof v != 'function') {
if (l < a.length) {
e(',');
}
g(i);
e(':');
g(v);
}
}
return e('}');
}
}
e('null');
return;
case 'number':
e(isFinite(x) ? +x : 'null');
return;
case 'string':
l = x.length;
e('"');
for (i = 0; i < l; i += 1) {
c = x.charAt(i);
if (c >= ' ') {
if (c == '\\' || c == '"') {
e('\\');
}
e(c);
} else {
switch (c) {
case '\b':
e('\\b');
break;
case '\f':
e('\\f');
break;
case '\n':
e('\\n');
break;
case '\r':
e('\\r');
break;
case '\t':
e('\\t');
break;
default:
c = c.charCodeAt();
e('\\u00' + Math.floor(c / 16).toString(16) +
(c % 16).toString(16));
}
}
}
e('"');
return;
case 'boolean':
e(String(x));
return;
default:
e('null');
return;
}
}
g(v);
return a.join('');
},
/*
Parse a JSON text, producing a JavaScript value.
*/
parse: function (text) {
var p = /^\s*(([,:{}\[\]])|"(\\.|[^\x00-\x1f"\\])*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)\s*/,
token,
operator;
function error(m, t) {
throw {
name: 'JSONError',
message: m,
text: t || operator || token
};
}
function next(b) {
if (b && b != operator) {
error("Expected '" + b + "'");
}
if (text) {
var t = p.exec(text);
if (t) {
if (t[2]) {
token = null;
operator = t[2];
} else {
operator = null;
try {
token = eval(t[1]);
} catch (e) {
error("Bad token", t[1]);
}
}
text = text.substring(t[0].length);
} else {
error("Unrecognized token", text);
}
} else {
token = operator = undefined;
}
}
function val() {
var k, o;
switch (operator) {
case '{':
next('{');
o = {};
if (operator != '}') {
for (;;) {
if (operator || typeof token != 'string') {
error("Missing key");
}
k = token;
next();
next(':');
o[k] = val();
if (operator != ',') {
break;
}
next(',');
}
}
next('}');
return o;
case '[':
next('[');
o = [];
if (operator != ']') {
for (;;) {
o.push(val());
if (operator != ',') {
break;
}
next(',');
}
}
next(']');
return o;
default:
if (operator !== null) {
error("Missing value");
}
k = token;
next();
return k;
}
}
next();
return val();
}
};
/***
!Setup the data serialization
***/
DataTiddler.format = "JSON";
DataTiddler.stringify = JSON.stringify;
DataTiddler.parse = JSON.parse;
//}}}
DiceRollerMacro
DiceRollerMacroTest
A minor Glancer for the Eye. Has done well for himself as a planner and tactician, and is able to dress in unassuming quality. Members of the Skullheart clan all have tattoos depicting a naked skull with a bloody heart clenched between it's teeth.
He reports to the Gazer [[Lord Haversham]].
/***
|''Name:''|DiceRollMacro |
|''Description:''|Inline dice roll macro. |
|''Version:''|0.1 |
|''Date:''|2008.08.18 |
|''Source:''|http://www.draugrheim.net/rpgwiki/rpgwiki.html |
|''Status''|stable |
|''Author:''|[[Martin Andersen|mailto:draugen@draugrheim.net]] |
|''Contributors''|[[Devon Jones|http://www.legolas.org/gmwiki/dev/gmwikidev.html]] |
|''Type:''|plugin |
|''License:''|GPL |
|''CoreVersion:''|2.4 |
!Description
Provides a <<roll>> macro that allows for inline dice rolls.
!Usage
{{{<<roll [Dice Expression] [Label]>>}}}
!!Parameters
!!!Dice Expression
The dice expression can be in 3 forms:
* {{{<<roll 1d20>>}}}; {{{<<roll 2d8+5>>}}}; {{{<<roll (1d20-2d6)+3d4>>}}}
* {{{<<roll +5>>}}} The number is added to a rolled D20. Used for skill checks, attack rolls etc. in the D20 system.
* {{{<<roll DC15>>}}} 1d20 is rolled against the DC. The result is how much it succeeded or missed by.
!!!Label
An optional label for the roll button. Defaults to the dice expression.
!Notes
Multiple expressions in parenthesies on the same level (e.g. (3d6+1d3)+3d4+(1d12+12)
!!Examples
{{{<<roll 1d20 "roll a D20">>}}}
<<roll 1d20 "roll a D20">>
{{{<<roll 1dF>>}}}
<<roll 1dF>>
{{{<<roll (1d6)dF>>}}}
<<roll (1d6)dF>>
!Revision history
!!v0.1 - 2008-08-18
Initial release.
!Code
***/
//{{{
if(!version.extensions.roll) {
version.extensions.roll = {
installed:true
};
version.extensions.roll = {
major: 0,
minor: 1,
revision: 0,
date: new Date(2008, 8, 18)
};
config.macros.roll = {};
config.macros.roll.onClick = function(e) {
var e = e || event;
var target = e.target || e.srcElement;
parseExp = new DiceRollParser(this.title);
//log roll result to messageArea
clearMessage();
displayMessage("Rolled " + parseExp.exp + ": " + parseExp.toString());
var resultbox = this.parentNode.lastChild;
resultbox.innerHTML = parseExp.result;
};
config.macros.roll.handler = function(place,macroName,params) {
// param 0: dice expression
// param 1: optional text label
var dicestring = params[0];
var title = params[1] ? params[1] : dicestring;
var rollwrapper = createTiddlyElement(place, "span", null, "rollwrapper");
createTiddlyButton(rollwrapper,title,dicestring,this.onClick,"rollbutton");
rollwrapper.appendChild(document.createTextNode(" "));
var resultbox = createTiddlyElement(rollwrapper, "span", null, "rollresult");
};
} //# end of 'install only once'
//}}}
/***
|''Name:''|DiceRollMacro |
|''Description:''|Inline dice roll macro. |
|''Version:''|0.1 |
|''Date:''|2008.08.18 |
|''Source:''|http://www.draugrheim.net/rpgwiki/rpgwiki.html |
|''Status''|stable |
|''Author:''|[[Martin Andersen|mailto:draugen@draugrheim.net]] |
|''Contributors''|[[Devon Jones|http://www.legolas.org/gmwiki/dev/gmwikidev.html]] |
|''Type:''|plugin |
|''License:''|GPL |
|''CoreVersion:''|2.4 |
!Revision history
|0.1|Initial release. Complete rewrite/refactor of original code. |
!Code
***/
function DiceRollParser(exp, prefix) {
this.exp = exp;
this.prefix = prefix ? prefix : "+";
this.subexps = [];
this.result = 0;
this.rolls = [];
this.dice = [];
this.parse(this.exp);
this.roll();
}
DiceRollParser.prototype.parse = function expParse(exp) {
var tests = {
// regexes contain extra parenthesises for pattern matching later
parens: /\((.*)\)/, // (<anything>)
parensDice: /\((.*)\)[dD](\dFf+)/,
checkLast: /^.+([\+\-])(\d+)$/, //<any string>+|-<number>
check: /^([\+\-])(\d+)$/, // +|-<number>
dc: /^[Dd][Cc](\d+)$/, // DC|Dc|dc|dC<number>
num: /^\d+$/, // <number>
complex: /(\d*)([dD])([\dfF]+)([\+\-]?)(.*)/, //<number>d|D[<number|f|F][+|-]<anything>
dice: /(\d*)([dD])([\d|fF]+)/ //<number>d|D[<number>|f|F]
};
if (tests.checkLast.test(exp)) {
var checkLastExp = tests.checkLast.exec(exp);
this.mod = checkLastExp[2];
if (checkLastExp[1] === "-") {
this.mod = this.mod * -1;
}
this.parse(exp.replace(/[\+\-]\d+$/, ""));
}
else if (tests.check.test(exp)) {// roll +|-x
var checkExp = tests.check.exec(exp);
this.mod = checkExp[2];
this.dice.push([new Dice()]);
if (checkExp[1] === "-") {
this.mod = this.mod * -1;
}
}
else if (tests.dc.test(exp)) {
var dcExp = tests.dc.exec(exp);
this.dc = dcExp[1];
this.dice.push([new Dice()]);
}
else if (tests.parens.test(exp)) {
// extract expression from parenthesies and evaluate
var parensExp = tests.parens.exec(exp);
this.subexp = new DiceRollParser(parensExp[1]);
// re-parse original expression with the evaluated result of the parenthesied expression
this.parse(exp.replace(tests.parens, this.subexp.result));
}
else if (tests.complex.test(exp)) {
var complexExp = tests.complex.exec(exp);
var count = complexExp[1];
var sides = complexExp[3];
var prefix = complexExp[4];
var subexp = complexExp[5];
this.dice.push([new Dice(count, new Die(sides))]);
if (tests.num.test(subexp)) {
this.mod = subexp;
if (prefix === "-") {
this.mod = this.mod * -1;
}
}
else if (tests.dice.test(subexp)) {
diceExp = tests.dice.exec(subexp);
count = diceExp[1];
sides = diceExp[3];
this.dice.push([new Dice(count, new Die(sides)), prefix]);
}
else {
this.parse(subexp);
}
}
};
DiceRollParser.prototype.roll = function () {
if (this.dice.length) {
for (var i in this.dice) {
if (this.dice.hasOwnProperty(i)) {
var dice = this.dice[i][0];
var prefix = this.dice[i][1];
if (prefix === "-") {
this.result -= dice.rolls.total;
for (var j = 0; j < dice.rolls.length; j++) {
var roll = dice.rolls[j];
this.rolls.push("(" + roll * -1 + ")");
}
}
else {
this.result += dice.rolls.total;
for (var k = 0; k < dice.rolls.length; k++) {
roll = dice.rolls[k];
this.rolls.push(roll);
}
}
}
}
}
if (this.subexp) {
//var subexpDice = new RegExp("\\(" + this.subexp.exp + "\\)[dD]\\dFf+");
var subexpDice = /\(.*\)[dD][\dFf]+/;
if (!subexpDice.test(this.exp)) {
this.result += this.subexp.result;
}
}
//add modifier
this.result += this.mod ? parseInt(this.mod, 10) : 0;
//subtract DC, if applicable
this.result -= this.dc ? parseInt(this.dc, 10) : 0;
return this.result;
};
DiceRollParser.prototype.toString = function () {
var isNegNum = /^\-\d+/;
var s = this.rolls.length ? this.rolls.join(' + ') + "" : "";
if (isNegNum.test(this.mod)) {
s += this.mod ? (s ? " + (" + this.mod + ")": "(" + this.mod + ")" ) : "";
}
else {
s += this.mod ? (s ? " + " + this.mod : this.mod ) : "";
}
s += this.dc ? " - " + this.dc : "";
if (this.subexp) {
var subexpDice = /\(.*\)[dD][\dFf]+/;
if (!subexpDice.test(this.exp)) {
s += " " + this.subexp.prefix + " (" + this.subexp.toString() + ")";
}
}
s += " = " + this.result;
return s;
};
DiceRollParser.prototype.toHtmlString = function () {
var s = "<dl>";
s += "<dt>Result</dd>";
s += "<dd c>" + this.toString() + "</dd>";
if (this.dice.length) {
s += "<dt>Dice</dd>";
for (i in this.dice) {
if(this.dice.hasOwnProperty(i)) {
s += "<dd>" + this.dice[i][0].toString() +"</dd>";
}
}
}
if (this.dc) {
s += "<dt>DC</dt>";
s += "<dd>" + this.dc + "</dd>";
}
if (this.mod) {
s += "<dt>Modifier</dt>";
s += "<dd>" + this.mod + "</dd>";
}
if (this.subexp) {
s += "<dt>Sub-expression</dt>";
s += "<dd>" + this.subexp.toHtmlString() + "</dd>";
}
s += "<dt>Expression</dt>";
s += "<dd>" + this.exp + "</dd>";
s += "</dl>";
return s;
}
/***
|''Name:''|DiceRollerPlugin |
|''Description:''|Dice roll library. |
|''Version:''|0.1.0 |
|''Date:''|August 2008 |
|''Source:''|http://www.draugrheim.net/rpgwiki/diceroller.js |
|''Author:''|[[Martin Andersen|mailto:draugen@draugrheim.net]] |
|''Credits''|Original code by [[Devon Jones|http://www.legolas.org/gmwiki/dev/gmwikidev.html]] |
|''Type:''|plugin |
|''License:''|GPL |
!Description
Dice roller utility class for RPGWiki. Handles dice of an arbitrary integer size as well as Fudge dice.
!Usage
!!Creating a single die
Create a new die object by using the {{{new}}} operator:
{{{
var die = new Die(); // will create a new 20-sided die and roll it
}}}
The Die constructor takes an optional parameter to specify the number of sides. This may be any positive integer as well as the letter 'f' (case insensitive) for Fudge dice. If the number of sides is omitted, it is assumed a D20 is wanted.
!!Creating a number of dice
Create a new dice object by using the {{{new}}} operator:
{{{
var dice = new Dice(3,die); // will create a collection of 3 20-sided dice
}}}
The Dice constructor's first parameter is the number of dice. The second parameter is a Die object. If the second parameter is omitted, a D20 is assumed.
!Revision history
|0.1 |Complete rewrite/refactor of code. |
!Code
***/
//{{{
if(!version.extensions.diceRoller) {
version.extensions.diceRoller = {installed:true};
version.extensions.diceRoller = { major: 0, minor: 1, revision: 0, date: new Date(2008, 07, 27) };
function Die(sides) {
this.sides = sides || 20;
this.roll();
}
Die.prototype.roll = function () {
var dieroll;
this.roll.result = 0;
if (this.sides === "F" || this.sides === "f") { // fudge die
dieroll = Math.floor(3 * Math.random()) - 1;
}
else if (!isNaN(parseInt(this.sides))) { // normal die
dieroll = Math.floor(this.sides * Math.random()) + 1;
}
this.roll.result += dieroll;
return this.roll.result;
};
function Dice(count, die) {
this.count = !isNaN(parseInt(count)) ? count : 1; // default to 1 die
this.die = die || new Die(); // with 20 sides
this.rolls = [];
this.roll();
}
Dice.prototype.roll = function () {
this.rolls = [];
this.rolls.total = 0;
for (var i = 0; i < this.count; i++) {
this.rolls.total += this.die.roll();
this.rolls.push(this.die.roll.result);
}
return this.rolls.total;
};
Dice.prototype.toString = function () {
var s = this.count + "d" + this.die.sides;
s += " (rolled " + this.rolls.join(" + ");
s += " = " + this.rolls.total +")";
return s;
}
} //# end of 'install only once'
//}}}
/***
|''Name:''|DisableWikiLinksPlugin|
|''Description:''|Allows you to disable TiddlyWiki's automatic linking of WikiWords|
|''Author:''|Martin Budden (mjbudden (at) gmail (dot) com)|
|''Source:''|http://www.martinswiki.com/#DisableWikiLinksPlugin |
|''CodeRepository:''|http://svn.tiddlywiki.org/Trunk/contributors/MartinBudden/plugins/DisableWikiLinksPlugin.js |
|''Version:''|0.1.3|
|''Date:''|Aug 5, 2006|
|''Comments:''|Please make comments at http://groups.google.co.uk/group/TiddlyWikiDev |
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]] |
|''~CoreVersion:''|2.1.0|
|''Disable WikiLinks''|<<option chkDisableWikiLinks>>|
***/
//{{{
// Ensure that the DisableWikiLinksPlugin is only installed once.
if(!version.extensions.DisableWikiLinksPlugin) {
version.extensions.DisableWikiLinksPlugin = {installed:true};
if(version.major < 2 || (version.major == 2 && version.minor < 1))
{alertAndThrow('DisableWikiLinksPlugin requires TiddlyWiki 2.1 or newer.');}
if (config.options.chkDisableWikiLinks==undefined)
{config.options.chkDisableWikiLinks = false;}
Tiddler.prototype.autoLinkWikiWords = function()
{
if(config.options.chkDisableWikiLinks==true)
{return false;}
return !this.isTagged('systemConfig') && !this.isTagged('excludeMissing');
};
} // end of 'install only once'
//}}}
Dwarf Ranger 2
Prods the [[ogre|Ogre Guard]] when the warehouses are threatened, goading into rage. Takes cover behind strategically placed crates while the ogre smashes intruders to bits.
|statblock|k
|>| //Initiative//| ''<<roll d20+6 '+6'>>'' | //AC//| ''15(19)'' |(10 +3 armor + 2 dex(+4 against giants)) |
|>| //Vitality//| ''20'' | //Touch//| ''12(16)'' |
|>| //Wounds//| ''14'' | //Flat-footed//| ''13(17)'' |
|>|>| ''//Abilities//'' | //Fortitude//| ''<<roll d20+5 '5'>>'' |(+3 base +2 con) |
| //Str//| 15 | ''+2'' | //Reflex//| ''<<roll d20+1 '+1'>>'' |(+3 base +2 dex) |
| //Dex//| 14 | ''+2'' | //Will//| ''<<roll d20+1 '+1'>>'' |(0 base 1 wis) |
| //Con//| 14 | ''+2'' |>| ''//Attacks//'' |//Damage// |
| //Int//| 10 | ''+0'' | //Prod//| ''+4'' |1d4+2 |
| //Wis//| 13 | ''+1'' | //Net//| ''+4'' |Target entangled (Break DC 50) |
| //Cha//| 6 | ''-2'' | //Shotgun//| ''+4'' |2d8 |
| ''//Skill//''| ''//Stat//'' | ''//Modifier//'' | ''//Ability//'' | ''//Ranks//'' |''//Misc//'' |
| //Handle Animal//| Cha | ''3'' | -2 | +5 |
| //Survival//| Wis | ''6'' | +1 | +5 |
| //Listen//| Wis | ''<<roll 1d20+6 '6'>>'' | +1 | +5 |
| //Spot//| Wis | ''<<roll 1d20+6 '6'>>'' | +1 | +5 |
| //Hide//| Dex | ''7'' | +2 | +5 |
| //Move Silently//| Dex | ''7 '' | +2 | +5 |
| Feats | Special |h
|Improved Initiative |Darkvision 60 ft |
|Combat Reflexes |[[Favored Enemy (Giant)|http://www.d20srd.org/srd/Classes/ranger.htm#favoredEnemy]] |
|Point-Blank Shot |Ranged Weapon Combat Style |
Type the text for 'Elixir of Life'
/***
|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;
}
//}}}
<<forEachTiddler
where
'tiddler.tags.contains("Faction")'
write
'"![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
/***
|''Name:''|ForEachTiddlerPlugin|
|''Version:''|1.0.8 (2007-04-12)|
|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|
|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|
|''Licence:''|[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]|
|''Copyright:''|© 2005-2007 [[abego Software|http://www.abego-software.de]]|
|''TiddlyWiki:''|1.2.38+, 2.0|
|''Browser:''|Firefox 1.0.4+; Firefox 1.5; InternetExplorer 6.0|
!Description
Create customizable lists, tables etc. for your selections of tiddlers. Specify the tiddlers to include and their order through a powerful language.
''Syntax:''
|>|{{{<<}}}''forEachTiddler'' [''in'' //tiddlyWikiPath//] [''where'' //whereCondition//] [''sortBy'' //sortExpression// [''ascending'' //or// ''descending'']] [''script'' //scriptText//] [//action// [//actionParameters//]]{{{>>}}}|
|//tiddlyWikiPath//|The filepath to the TiddlyWiki the macro should work on. When missing the current TiddlyWiki is used.|
|//whereCondition//|(quoted) JavaScript boolean expression. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|
|//sortExpression//|(quoted) JavaScript expression returning "comparable" objects (using '{{{<}}}','{{{>}}}','{{{==}}}'. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|
|//scriptText//|(quoted) JavaScript text. Typically defines JavaScript functions that are called by the various JavaScript expressions (whereClause, sortClause, action arguments,...)|
|//action//|The action that should be performed on every selected tiddler, in the given order. By default the actions [[addToList|AddToListAction]] and [[write|WriteAction]] are supported. When no action is specified [[addToList|AddToListAction]] is used.|
|//actionParameters//|(action specific) parameters the action may refer while processing the tiddlers (see action descriptions for details). <<tiddler [[JavaScript in actionParameters]]>>|
|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|
See details see [[ForEachTiddlerMacro]] and [[ForEachTiddlerExamples]].
!Revision history
* v1.0.8 (2007-04-12)
** Adapted to latest TiddlyWiki 2.2 Beta importTiddlyWiki API (introduced with changeset 2004). TiddlyWiki 2.2 Beta builds prior to changeset 2004 are no longer supported (but TiddlyWiki 2.1 and earlier, of cause)
* v1.0.7 (2007-03-28)
** Also support "pre" formatted TiddlyWikis (introduced with TW 2.2) (when using "in" clause to work on external tiddlers)
* v1.0.6 (2006-09-16)
** Context provides "viewerTiddler", i.e. the tiddler used to view the macro. Most times this is equal to the "inTiddler", but when using the "tiddler" macro both may be different.
** Support "begin", "end" and "none" expressions in "write" action
* v1.0.5 (2006-02-05)
** Pass tiddler containing the macro with wikify, context object also holds reference to tiddler containing the macro ("inTiddler"). Thanks to SimonBaird.
** Support Firefox 1.5.0.1
** Internal
*** Make "JSLint" conform
*** "Only install once"
* v1.0.4 (2006-01-06)
** Support TiddlyWiki 2.0
* v1.0.3 (2005-12-22)
** Features:
*** Write output to a file supports multi-byte environments (Thanks to Bram Chen)
*** Provide API to access the forEachTiddler functionality directly through JavaScript (see getTiddlers and performMacro)
** Enhancements:
*** Improved error messages on InternetExplorer.
* v1.0.2 (2005-12-10)
** Features:
*** context object also holds reference to store (TiddlyWiki)
** Fixed Bugs:
*** ForEachTiddler 1.0.1 has broken support on win32 Opera 8.51 (Thanks to BrunoSabin for reporting)
* v1.0.1 (2005-12-08)
** Features:
*** Access tiddlers stored in separated TiddlyWikis through the "in" option. I.e. you are no longer limited to only work on the "current TiddlyWiki".
*** Write output to an external file using the "toFile" option of the "write" action. With this option you may write your customized tiddler exports.
*** Use the "script" section to define "helper" JavaScript functions etc. to be used in the various JavaScript expressions (whereClause, sortClause, action arguments,...).
*** Access and store context information for the current forEachTiddler invocation (through the build-in "context" object) .
*** Improved script evaluation (for where/sort clause and write scripts).
* v1.0.0 (2005-11-20)
** initial version
!Code
***/
//{{{
//============================================================================
//============================================================================
// ForEachTiddlerPlugin
//============================================================================
//============================================================================
// Only install once
if (!version.extensions.ForEachTiddlerPlugin) {
if (!window.abego) window.abego = {};
version.extensions.ForEachTiddlerPlugin = {
major: 1, minor: 0, revision: 8,
date: new Date(2007,3,12),
source: "http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin",
licence: "[[BSD open source license (abego Software)|http://www.abego-software.de/legal/apl-v10.html]]",
copyright: "Copyright (c) abego Software GmbH, 2005-2007 (www.abego-software.de)"
};
// For backward compatibility with TW 1.2.x
//
if (!TiddlyWiki.prototype.forEachTiddler) {
TiddlyWiki.prototype.forEachTiddler = function(callback) {
for(var t in this.tiddlers) {
callback.call(this,t,this.tiddlers[t]);
}
};
}
//============================================================================
// forEachTiddler Macro
//============================================================================
version.extensions.forEachTiddler = {
major: 1, minor: 0, revision: 8, date: new Date(2007,3,12), provider: "http://tiddlywiki.abego-software.de"};
// ---------------------------------------------------------------------------
// Configurations and constants
// ---------------------------------------------------------------------------
config.macros.forEachTiddler = {
// Standard Properties
label: "forEachTiddler",
prompt: "Perform actions on a (sorted) selection of tiddlers",
// actions
actions: {
addToList: {},
write: {}
}
};
// ---------------------------------------------------------------------------
// The forEachTiddler Macro Handler
// ---------------------------------------------------------------------------
config.macros.forEachTiddler.getContainingTiddler = function(e) {
while(e && !hasClass(e,"tiddler"))
e = e.parentNode;
var title = e ? e.getAttribute("tiddler") : null;
return title ? store.getTiddler(title) : null;
};
config.macros.forEachTiddler.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
// config.macros.forEachTiddler.traceMacroCall(place,macroName,params,wikifier,paramString,tiddler);
if (!tiddler) tiddler = config.macros.forEachTiddler.getContainingTiddler(place);
// --- Parsing ------------------------------------------
var i = 0; // index running over the params
// Parse the "in" clause
var tiddlyWikiPath = undefined;
if ((i < params.length) && params[i] == "in") {
i++;
if (i >= params.length) {
this.handleError(place, "TiddlyWiki path expected behind 'in'.");
return;
}
tiddlyWikiPath = this.paramEncode((i < params.length) ? params[i] : "");
i++;
}
// Parse the where clause
var whereClause ="true";
if ((i < params.length) && params[i] == "where") {
i++;
whereClause = this.paramEncode((i < params.length) ? params[i] : "");
i++;
}
// Parse the sort stuff
var sortClause = null;
var sortAscending = true;
if ((i < params.length) && params[i] == "sortBy") {
i++;
if (i >= params.length) {
this.handleError(place, "sortClause missing behind 'sortBy'.");
return;
}
sortClause = this.paramEncode(params[i]);
i++;
if ((i < params.length) && (params[i] == "ascending" || params[i] == "descending")) {
sortAscending = params[i] == "ascending";
i++;
}
}
// Parse the script
var scriptText = null;
if ((i < params.length) && params[i] == "script") {
i++;
scriptText = this.paramEncode((i < params.length) ? params[i] : "");
i++;
}
// Parse the action.
// When we are already at the end use the default action
var actionName = "addToList";
if (i < params.length) {
if (!config.macros.forEachTiddler.actions[params[i]]) {
this.handleError(place, "Unknown action '"+params[i]+"'.");
return;
} else {
actionName = params[i];
i++;
}
}
// Get the action parameter
// (the parsing is done inside the individual action implementation.)
var actionParameter = params.slice(i);
// --- Processing ------------------------------------------
try {
this.performMacro({
place: place,
inTiddler: tiddler,
whereClause: whereClause,
sortClause: sortClause,
sortAscending: sortAscending,
actionName: actionName,
actionParameter: actionParameter,
scriptText: scriptText,
tiddlyWikiPath: tiddlyWikiPath});
} catch (e) {
this.handleError(place, e);
}
};
// Returns an object with properties "tiddlers" and "context".
// tiddlers holds the (sorted) tiddlers selected by the parameter,
// context the context of the execution of the macro.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlersAndContext = function(parameter) {
var context = config.macros.forEachTiddler.createContext(parameter.place, parameter.whereClause, parameter.sortClause, parameter.sortAscending, parameter.actionName, parameter.actionParameter, parameter.scriptText, parameter.tiddlyWikiPath, parameter.inTiddler);
var tiddlyWiki = parameter.tiddlyWikiPath ? this.loadTiddlyWiki(parameter.tiddlyWikiPath) : store;
context["tiddlyWiki"] = tiddlyWiki;
// Get the tiddlers, as defined by the whereClause
var tiddlers = this.findTiddlers(parameter.whereClause, context, tiddlyWiki);
context["tiddlers"] = tiddlers;
// Sort the tiddlers, when sorting is required.
if (parameter.sortClause) {
this.sortTiddlers(tiddlers, parameter.sortClause, parameter.sortAscending, context);
}
return {tiddlers: tiddlers, context: context};
};
// Returns the (sorted) tiddlers selected by the parameter.
//
// The action is not yet performed.
//
// @parameter see performMacro
//
config.macros.forEachTiddler.getTiddlers = function(parameter) {
return this.getTiddlersAndContext(parameter).tiddlers;
};
// Performs the macros with the given parameter.
//
// @param parameter holds the parameter of the macro as separate properties.
// The following properties are supported:
//
// place
// whereClause
// sortClause
// sortAscending
// actionName
// actionParameter
// scriptText
// tiddlyWikiPath
//
// All properties are optional.
// For most actions the place property must be defined.
//
config.macros.forEachTiddler.performMacro = function(parameter) {
var tiddlersAndContext = this.getTiddlersAndContext(parameter);
// Perform the action
var actionName = parameter.actionName ? parameter.actionName : "addToList";
var action = config.macros.forEachTiddler.actions[actionName];
if (!action) {
this.handleError(parameter.place, "Unknown action '"+actionName+"'.");
return;
}
var actionHandler = action.handler;
actionHandler(parameter.place, tiddlersAndContext.tiddlers, parameter.actionParameter, tiddlersAndContext.context);
};
// ---------------------------------------------------------------------------
// The actions
// ---------------------------------------------------------------------------
// Internal.
//
// --- The addToList Action -----------------------------------------------
//
config.macros.forEachTiddler.actions.addToList.handler = function(place, tiddlers, parameter, context) {
// Parse the parameter
var p = 0;
// Check for extra parameters
if (parameter.length > p) {
config.macros.forEachTiddler.createExtraParameterErrorElement(place, "addToList", parameter, p);
return;
}
// Perform the action.
var list = document.createElement("ul");
place.appendChild(list);
for (var i = 0; i < tiddlers.length; i++) {
var tiddler = tiddlers[i];
var listItem = document.createElement("li");
list.appendChild(listItem);
createTiddlyLink(listItem, tiddler.title, true);
}
};
abego.parseNamedParameter = function(name, parameter, i) {
var beginExpression = null;
if ((i < parameter.length) && parameter[i] == name) {
i++;
if (i >= parameter.length) {
throw "Missing text behind '%0'".format([name]);
}
return config.macros.forEachTiddler.paramEncode(parameter[i]);
}
return null;
}
// Internal.
//
// --- The write Action ---------------------------------------------------
//
config.macros.forEachTiddler.actions.write.handler = function(place, tiddlers, parameter, context) {
// Parse the parameter
var p = 0;
if (p >= parameter.length) {
this.handleError(place, "Missing expression behind 'write'.");
return;
}
var textExpression = config.macros.forEachTiddler.paramEncode(parameter[p]);
p++;
// Parse the "begin" option
var beginExpression = abego.parseNamedParameter("begin", parameter, p);
if (beginExpression !== null)
p += 2;
var endExpression = abego.parseNamedParameter("end", parameter, p);
if (endExpression !== null)
p += 2;
var noneExpression = abego.parseNamedParameter("none", parameter, p);
if (noneExpression !== null)
p += 2;
// Parse the "toFile" option
var filename = null;
var lineSeparator = undefined;
if ((p < parameter.length) && parameter[p] == "toFile") {
p++;
if (p >= parameter.length) {
this.handleError(place, "Filename expected behind 'toFile' of 'write' action.");
return;
}
filename = config.macros.forEachTiddler.getLocalPath(config.macros.forEachTiddler.paramEncode(parameter[p]));
p++;
if ((p < parameter.length) && parameter[p] == "withLineSeparator") {
p++;
if (p >= parameter.length) {
this.handleError(place, "Line separator text expected behind 'withLineSeparator' of 'write' action.");
return;
}
lineSeparator = config.macros.forEachTiddler.paramEncode(parameter[p]);
p++;
}
}
// Check for extra parameters
if (parameter.length > p) {
config.macros.forEachTiddler.createExtraParameterErrorElement(place, "write", parameter, p);
return;
}
// Perform the action.
var func = config.macros.forEachTiddler.getEvalTiddlerFunction(textExpression, context);
var count = tiddlers.length;
var text = "";
if (count > 0 && beginExpression)
text += config.macros.forEachTiddler.getEvalTiddlerFunction(beginExpression, context)(undefined, context, count, undefined);
for (var i = 0; i < count; i++) {
var tiddler = tiddlers[i];
text += func(tiddler, context, count, i);
}
if (count > 0 && endExpression)
text += config.macros.forEachTiddler.getEvalTiddlerFunction(endExpression, context)(undefined, context, count, undefined);
if (count == 0 && noneExpression)
text += config.macros.forEachTiddler.getEvalTiddlerFunction(noneExpression, context)(undefined, context, count, undefined);
if (filename) {
if (lineSeparator !== undefined) {
lineSeparator = lineSeparator.replace(/\\n/mg, "\n").replace(/\\r/mg, "\r");
text = text.replace(/\n/mg,lineSeparator);
}
saveFile(filename, convertUnicodeToUTF8(text));
} else {
var wrapper = createTiddlyElement(place, "span");
wikify(text, wrapper, null/* highlightRegExp */, context.inTiddler);
}
};
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
// Internal.
//
config.macros.forEachTiddler.createContext = function(placeParam, whereClauseParam, sortClauseParam, sortAscendingParam, actionNameParam, actionParameterParam, scriptText, tiddlyWikiPathParam, inTiddlerParam) {
return {
place : placeParam,
whereClause : whereClauseParam,
sortClause : sortClauseParam,
sortAscending : sortAscendingParam,
script : scriptText,
actionName : actionNameParam,
actionParameter : actionParameterParam,
tiddlyWikiPath : tiddlyWikiPathParam,
inTiddler : inTiddlerParam, // the tiddler containing the <<forEachTiddler ...>> macro call.
viewerTiddler : config.macros.forEachTiddler.getContainingTiddler(placeParam) // the tiddler showing the forEachTiddler result
};
};
// Internal.
//
// Returns a TiddlyWiki with the tiddlers loaded from the TiddlyWiki of
// the given path.
//
config.macros.forEachTiddler.loadTiddlyWiki = function(path, idPrefix) {
if (!idPrefix) {
idPrefix = "store";
}
var lenPrefix = idPrefix.length;
// Read the content of the given file
var content = loadFile(this.getLocalPath(path));
if(content === null) {
throw "TiddlyWiki '"+path+"' not found.";
}
var tiddlyWiki = new TiddlyWiki();
// Starting with TW 2.2 there is a helper function to import the tiddlers
if (tiddlyWiki.importTiddlyWiki) {
if (!tiddlyWiki.importTiddlyWiki(content))
throw "File '"+path+"' is not a TiddlyWiki.";
tiddlyWiki.dirty = false;
return tiddlyWiki;
}
// The legacy code, for TW < 2.2
// Locate the storeArea div's
var posOpeningDiv = content.indexOf(startSaveArea);
var posClosingDiv = content.lastIndexOf(endSaveArea);
if((posOpeningDiv == -1) || (posClosingDiv == -1)) {
throw "File '"+path+"' is not a TiddlyWiki.";
}
var storageText = content.substr(posOpeningDiv + startSaveArea.length, posClosingDiv);
// Create a "div" element that contains the storage text
var myStorageDiv = document.createElement("div");
myStorageDiv.innerHTML = storageText;
myStorageDiv.normalize();
// Create all tiddlers in a new TiddlyWiki
// (following code is modified copy of TiddlyWiki.prototype.loadFromDiv)
var store = myStorageDiv.childNodes;
for(var t = 0; t < store.length; t++) {
var e = store[t];
var title = null;
if(e.getAttribute)
title = e.getAttribute("tiddler");
if(!title && e.id && e.id.substr(0,lenPrefix) == idPrefix)
title = e.id.substr(lenPrefix);
if(title && title !== "") {
var tiddler = tiddlyWiki.createTiddler(title);
tiddler.loadFromDiv(e,title);
}
}
tiddlyWiki.dirty = false;
return tiddlyWiki;
};
// Internal.
//
// Returns a function that has a function body returning the given javaScriptExpression.
// The function has the parameters:
//
// (tiddler, context, count, index)
//
config.macros.forEachTiddler.getEvalTiddlerFunction = function (javaScriptExpression, context) {
var script = context["script"];
var functionText = "var theFunction = function(tiddler, context, count, index) { return "+javaScriptExpression+"}";
var fullText = (script ? script+";" : "")+functionText+";theFunction;";
return eval(fullText);
};
// Internal.
//
config.macros.forEachTiddler.findTiddlers = function(whereClause, context, tiddlyWiki) {
var result = [];
var func = config.macros.forEachTiddler.getEvalTiddlerFunction(whereClause, context);
tiddlyWiki.forEachTiddler(function(title,tiddler) {
if (func(tiddler, context, undefined, undefined)) {
result.push(tiddler);
}
});
return result;
};
// Internal.
//
config.macros.forEachTiddler.createExtraParameterErrorElement = function(place, actionName, parameter, firstUnusedIndex) {
var message = "Extra parameter behind '"+actionName+"':";
for (var i = firstUnusedIndex; i < parameter.length; i++) {
message += " "+parameter[i];
}
this.handleError(place, message);
};
// Internal.
//
config.macros.forEachTiddler.sortAscending = function(tiddlerA, tiddlerB) {
var result =
(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue)
? 0
: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
? -1
: +1;
return result;
};
// Internal.
//
config.macros.forEachTiddler.sortDescending = function(tiddlerA, tiddlerB) {
var result =
(tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue)
? 0
: (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)
? +1
: -1;
return result;
};
// Internal.
//
config.macros.forEachTiddler.sortTiddlers = function(tiddlers, sortClause, ascending, context) {
// To avoid evaluating the sortClause whenever two items are compared
// we pre-calculate the sortValue for every item in the array and store it in a
// temporary property ("forEachTiddlerSortValue") of the tiddlers.
var func = config.macros.forEachTiddler.getEvalTiddlerFunction(sortClause, context);
var count = tiddlers.length;
var i;
for (i = 0; i < count; i++) {
var tiddler = tiddlers[i];
tiddler.forEachTiddlerSortValue = func(tiddler,context, undefined, undefined);
}
// Do the sorting
tiddlers.sort(ascending ? this.sortAscending : this.sortDescending);
// Delete the temporary property that holds the sortValue.
for (i = 0; i < tiddlers.length; i++) {
delete tiddlers[i].forEachTiddlerSortValue;
}
};
// Internal.
//
config.macros.forEachTiddler.trace = function(message) {
displayMessage(message);
};
// Internal.
//
config.macros.forEachTiddler.traceMacroCall = function(place,macroName,params) {
var message ="<<"+macroName;
for (var i = 0; i < params.length; i++) {
message += " "+params[i];
}
message += ">>";
displayMessage(message);
};
// Internal.
//
// Creates an element that holds an error message
//
config.macros.forEachTiddler.createErrorElement = function(place, exception) {
var message = (exception.description) ? exception.description : exception.toString();
return createTiddlyElement(place,"span",null,"forEachTiddlerError","<<forEachTiddler ...>>: "+message);
};
// Internal.
//
// @param place [may be null]
//
config.macros.forEachTiddler.handleError = function(place, exception) {
if (place) {
this.createErrorElement(place, exception);
} else {
throw exception;
}
};
// Internal.
//
// Encodes the given string.
//
// Replaces
// "$))" to ">>"
// "$)" to ">"
//
config.macros.forEachTiddler.paramEncode = function(s) {
var reGTGT = new RegExp("\\$\\)\\)","mg");
var reGT = new RegExp("\\$\\)","mg");
return s.replace(reGTGT, ">>").replace(reGT, ">");
};
// Internal.
//
// Returns the given original path (that is a file path, starting with "file:")
// as a path to a local file, in the systems native file format.
//
// Location information in the originalPath (i.e. the "#" and stuff following)
// is stripped.
//
config.macros.forEachTiddler.getLocalPath = function(originalPath) {
// Remove any location part of the URL
var hashPos = originalPath.indexOf("#");
if(hashPos != -1)
originalPath = originalPath.substr(0,hashPos);
// Convert to a native file format assuming
// "file:///x:/path/path/path..." - pc local file --> "x:\path\path\path..."
// "file://///server/share/path/path/path..." - FireFox pc network file --> "\\server\share\path\path\path..."
// "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."
// "file://server/share/path/path/path..." - pc network file --> "\\server\share\path\path\path..."
var localPath;
if(originalPath.charAt(9) == ":") // pc local file
localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
else if(originalPath.indexOf("file://///") === 0) // FireFox pc network file
localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
else if(originalPath.indexOf("file:///") === 0) // mac/unix local file
localPath = unescape(originalPath.substr(7));
else if(originalPath.indexOf("file:/") === 0) // mac/unix local file
localPath = unescape(originalPath.substr(5));
else // pc network file
localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
return localPath;
};
// ---------------------------------------------------------------------------
// Stylesheet Extensions (may be overridden by local StyleSheet)
// ---------------------------------------------------------------------------
//
setStylesheet(
".forEachTiddlerError{color: #ffffff;background-color: #880000;}",
"forEachTiddler");
//============================================================================
// End of forEachTiddler Macro
//============================================================================
//============================================================================
// String.startsWith Function
//============================================================================
//
// Returns true if the string starts with the given prefix, false otherwise.
//
version.extensions["String.startsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.startsWith = function(prefix) {
var n = prefix.length;
return (this.length >= n) && (this.slice(0, n) == prefix);
};
//============================================================================
// String.endsWith Function
//============================================================================
//
// Returns true if the string ends with the given suffix, false otherwise.
//
version.extensions["String.endsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.endsWith = function(suffix) {
var n = suffix.length;
return (this.length >= n) && (this.right(n) == suffix);
};
//============================================================================
// String.contains Function
//============================================================================
//
// Returns true when the string contains the given substring, false otherwise.
//
version.extensions["String.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
String.prototype.contains = function(substring) {
return this.indexOf(substring) >= 0;
};
//============================================================================
// Array.indexOf Function
//============================================================================
//
// Returns the index of the first occurance of the given item in the array or
// -1 when no such item exists.
//
// @param item [may be null]
//
version.extensions["Array.indexOf"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.indexOf = function(item) {
for (var i = 0; i < this.length; i++) {
if (this[i] == item) {
return i;
}
}
return -1;
};
//============================================================================
// Array.contains Function
//============================================================================
//
// Returns true when the array contains the given item, otherwise false.
//
// @param item [may be null]
//
version.extensions["Array.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.contains = function(item) {
return (this.indexOf(item) >= 0);
};
//============================================================================
// Array.containsAny Function
//============================================================================
//
// Returns true when the array contains at least one of the elements
// of the item. Otherwise (or when items contains no elements) false is returned.
//
version.extensions["Array.containsAny"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAny = function(items) {
for(var i = 0; i < items.length; i++) {
if (this.contains(items[i])) {
return true;
}
}
return false;
};
//============================================================================
// Array.containsAll Function
//============================================================================
//
// Returns true when the array contains all the items, otherwise false.
//
// When items is null false is returned (even if the array contains a null).
//
// @param items [may be null]
//
version.extensions["Array.containsAll"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};
//
Array.prototype.containsAll = function(items) {
for(var i = 0; i < items.length; i++) {
if (!this.contains(items[i])) {
return false;
}
}
return true;
};
} // of "install only once"
// Used Globals (for JSLint) ==============
// ... DOM
/*global document */
// ... TiddlyWiki Core
/*global convertUnicodeToUTF8, createTiddlyElement, createTiddlyLink,
displayMessage, endSaveArea, hasClass, loadFile, saveFile,
startSaveArea, store, wikify */
//}}}
/***
!Licence and Copyright
Copyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
Neither the name of abego Software nor the names of its contributors may be
used to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
***/
//{{{
config.macros.tags.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
params = paramString.parseParams("anon",null,true,false,false);
var title = getParam(params,"anon","");
if(title && store.tiddlerExists(title))
tiddler = store.getTiddler(title);
var sep = getParam(params,"sep"," ");
var lingo = config.views.wikified.tag;
if (tiddler.tags.length > 0) {
var ul = createTiddlyElement(place,"ul");
var prompt = lingo.labelTags;
createTiddlyElement(ul,"li",null,"listTitle",prompt.format([tiddler.title]));
for(var t=0; t<tiddler.tags.length; t++) {
createTagButton(createTiddlyElement(ul,"li"),tiddler.tags[t],tiddler.title);
if(t<tiddler.tags.length-1)
createTiddlyText(ul,sep);
}
}
};
config.macros.tagging.handler = function(place,macroName,params,wikifier,paramString,tiddler)
{
params = paramString.parseParams("anon",null,true,false,false);
var title = getParam(params,"anon","");
if(title == "" && tiddler instanceof Tiddler)
title = tiddler.title;
var sep = getParam(params,"sep"," ");
var tagged = store.getTaggedTiddlers(title);
if (tagged.length > 0) {
var ul = createTiddlyElement(place,"ul");
ul.setAttribute("title",this.tooltip.format([title]));
var prompt = this.label;
createTiddlyElement(ul,"li",null,"listTitle",prompt.format([title,tagged.length]));
for(var t=0; t<tagged.length; t++) {
createTiddlyLink(createTiddlyElement(ul,"li"),tagged[t].title,true);
if(t<tagged.length-1)
createTiddlyText(ul,sep);
}
}
};
//}}}
/***
|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);
}}
});
//}}}
Lookouts, 3 on rooftops, 2 on patrol
|statblock|k
|>| //Initiative//| ''<<roll 1d20+5 '5'>>'' | //AC//| ''11'' |(10 + 1 dex) |
|>| //Vitality//| ''8'' | //Touch//| ''11'' |
|>| //Wounds//| ''10'' | //Flat-footed//| ''10'' |
|>|>| ''//Abilities//'' | //Fortitude//| ''<<roll 1d20+2 '2'>>'' |(+2 base) |
| //Str//| 8 | ''<<roll 1d20-1 '-1'>>'' | //Reflex//| ''<<roll 1d20+1 '1'>>'' |(+1 dex) |
| //Dex//| 12 | ''<<roll 1d20+1 '+1'>'' | //Will//| ''<<roll 1d20+1 '1'>>'' |(+1 wis) |
| //Con//| 10 | ''<<roll 1d20 '+0'>>'' |>| ''//Attacks//'' |//Damage// |
| //Int//| 11 | ''<<roll 1d20 '+0'>>'' | //Club//| ''<<roll 1d20+1 '+1'>>'' |<<roll 1d6>> |
| //Wis//| 13 | ''<<roll 1d20+1 '+1'>>'' | //Revolver//| ''<<roll 1d20+3 '+3'>>'' |<<roll 2d6>> |
| //Cha//| 9 | ''<<roll 1d20-1 '-1'>>'' |
| ''//Skill//''| ''//Stat//'' | ''//Modifier//'' | ''//Ability//'' | ''//Ranks//'' |''//Feats//'' |
| //Listen//| Wis | ''<<roll 1d20+3 '3'>>'' | +1 | +2 |Improved Initiative |
| //Spot//| Wis | ''<<roll 1d20+3 '3'>>'' | +1 | +2 |Point-Blank Shot |
Generic human warrior. Alter abilities to fit the situtation.
|statblock|k
|>| //Initiative//| ''<<roll 1d20+5 '5'>>'' | //AC//| ''11'' |(10 + 1 dex) |
|>| //Vitality//| ''8'' | //Touch//| ''11'' |
|>| //Wounds//| ''10'' | //Flat-footed//| ''10'' |
|>|>| ''//Abilities//'' | //Fortitude//| ''<<roll 1d20+2 '2'>>'' |(+2 base) |
| //Str//| 8 | ''<<roll 1d20-1 '-1'>>'' | //Reflex//| ''<<roll 1d20+1 '1'>>'' |(+1 dex) |
| //Dex//| 12 | ''<<roll 1d20+1 '+1'>'' | //Will//| ''<<roll 1d20+1 '1'>>'' |(+1 wis) |
| //Con//| 10 | ''<<roll 1d20 '+0'>>'' |>| ''//Attacks//'' |//Damage// |
| //Int//| 11 | ''<<roll 1d20 '+0'>>'' | //Club//| ''<<roll 1d20+1 '+1'>>'' |1d6 |
| //Wis//| 13 | ''<<roll 1d20+1 '+1'>>'' | //Revolver//| ''<<roll 1d20+3 '3'>>'' |2d6 |
| //Cha//| 9 | ''<<roll 1d20-1 '-1'>>'' |
| ''//Skill//''| ''//Stat//'' | ''//Modifier//'' | ''//Ability//'' | ''//Ranks//'' |''//Feats//'' |
| //Listen//| Wis | ''<<roll 1d20+3 '3'>>'' | +1 | +2 |Improved Initiative |
| //Spot//| Wis | ''<<roll 1d20+3 '3'>>'' | +1 | +2 |Point-Blank Shot |
* Monthly wage of 5 pounds
* hired for one year with option to extend contract.
* Bonus for job well done.
* Wage may be changed if job performance is unacceptable.
* Lodging included; Cellar and top story of limits; no visitors.
Hired to help the contractor with tasks including finding artifacts and similar, along with protection if need be. Miscellaneous jobs may occur, as well as travel abroad.
<<forEachTiddler
where
'tiddler.tags.contains("Iosef\'s Research")'
sortBy
'(tiddler.title.toLowerCase())'
write
'"!![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
<<forEachTiddler
where
'tiddler.tags.contains("Items")'
write
'"!![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
James (Norfinwen is his elven name) is a half-elven who has served the [[Tesla family|The Tesla Family]] as butler for nearly 5 centuries. He is also known in the streets of London as John.
|''Type:''|file|
|''URL:''|http://knighjm.googlepages.com/knightnet-default-tw.html|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
Mundane valuables worth £12000.
!Magic Items
* [[Ring of Communication]]
* Amulet of Tears (Magic Item Compendium p 70)
* Mirror of Suggestion (MIC p 165)
* Cloak of Elvenkind
* Tome of Clear Thought +3
* Dagger, keen
Stolen from a kobold arrow trap in session 3, [[James]] has applied for a patent for it in [[Iosef]]'s name.
The concept was sold to a German weapons manufacturer, who was very interested in licensing the technology for use in their new line of autonomous robotical mechalogic --soldiers-- workers.
Owned by [[Günther Krupp]], a half-elven with the ultimate goal of combining technology and magic to create semisentient --soldiers-- menial workers.
|''Type:''|file|
|''URL:''|http://tw.lewcid.org/|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
Soot-stained walls and [[smog-filled|London Fog]] air. Industrial laborers live in squalor, in contrast to the fine gentlemen with great estates, [[steam-powered|Steam Power]] carriages and [[Tick|file://../inp.html#Exotics]] bodyguards.
Free or escaped ticks gather in ghettos, seeking comfort among their own kind. The fight for survival is tough, given the swollen population. Territorial disputes are frequent. The authorities seldom interfere.
The harsh order the crime lords and their henchmen enforce in their turf gives them some respect among the poor.
The London fog creates great disadvantage for the city's inhabitants.
* Obscures sight up to 15ft (<<roll 1d10 '10%'>> miss chance)
* Creatures more than 15 ft away have [[total concealment|http://www.d20srd.org/srd/combat/combatModifiers.htm#totalConcealment]]
Terrance Cavendish is infamous among the gentlemen of London for being... foolish, blindly following every get-richer-quickly scheme he hears about or invents. His reputation notwithstanding, Lord Cavendish never seems to run out of funding for his mad pursuits.
Andrew Haversham is a Gazer for the Eye (or so it is rumored). Hands out Rings of Communication to his most trusted underlings.
Eugene Thacker has rebuilt his family's fortune by successfull investments into the colonies. A shrewd business man, Lord Thacker has considerable influence as a member of the [[Governing Council|The Governing Council]].
[[The Story]] [[The Cast]] [[The City]]
|''Type:''|file|
|''URL:''|http://www.martinswiki.com/|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
|''Type:''|file|
|''URL:''|http://mptw.tiddlyspot.com/|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
A bugbear Gazer for the Eye.
//{{{
if(!version.extensions.npcGenPlugin) { // install only once
version.extensions.npcGenPlugin = {installed:true};
npc = {}; // base class
npc.race = "Human";
npc.class = "Fighter";
npc.abilities = array();
npc.classSkills = array();
npc.rollStats = function(mode) {
// mode = one of: elite array, non-elite array, 4d6 drop low, 3d6, point-buy
}
npc.addClass = function();
npc.setRace = function();
} // end install only once
//}}}
!ViewTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'>
<span class='title' macro='view title'></span>
</div>
<div class='tiddlersidebar'>
<dl>
<dt>Creator</dt>
<dd macro='view modifier link'></dd>
</dl>
<dl class='rpgdata' macro='showWhenTagged "The Story" '>
<dt>Ingame Date</dt>
<dd macro='view gamemonth' class='rpgmonth'></dd>
<dd macro='view gameday' class='rpgday'></dd>
<dd macro='view gameyear' class='rpgyear'></dd>
<dt>Offgame Date</dt>
<dd macro='view realmonth' class='rpgmonth'></dd>
<dd macro='view realday' class='rpgday'></dd>
<dd macro='view realyear' class='rpgyear'></dd>
</dl>
<dl class='rpgdata' macro='showWhenTagged "Faction" '>
<dt>Leader</dt>
<dd macro='view factionleader link'></dd>
<dt>NPC(s)</dt>
<dd macro='view factionnpc wikified'></dd>
<dt>Ally/ies</dt>
<dd macro='view factionallies wikified'></dd>
<dt>Enemy/ies</dt>
<dd macro='view factionopponents wikified'></dd>
</dl>
<dl class='rpgdata' macro='showWhenTagged "PC" '>
<dt>Contacts</dt>
<dd macro='view contacts wikified'></dd>
</dl>
<span class='tagged' macro='tags'></span>
<span class='tagging' macro='tagging'></span>
</div>
<div class='viewer'>
<span macro='view text wikified'></span>
</div>
<div class='tiddlerfooter'>
Last modified <span macro='view modified date'></span>.
</div>
<!--}}}-->
!EditTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'>
<span class='title' macro='view title'></span>
</div>
<div class='tiddlersidebar'>
<dl>
<dt>Creator</dt>
<dd macro='view modifier link'></dd>
</dl>
<form macro='showWhenTagged "The Story" '>
<fieldset>
<legend>Ingame Date</legend>
<label>Year <span macro='edit gameyear'></span></label>
<label>Month <span macro='edit gamemonth'></span>
<label>Day <span macro='edit gameday'></span>
</fieldset>
<fieldset>
<legend>Offgame Date</legend>
<label>Year <span macro='edit realyear'></span>
<label>Month <span macro='edit realmonth'></span>
<label>Day <span macro='edit realday'></span>
</fieldset>
</form>
<form macro='showWhenTagged Faction'>
<label>Faction Leader <span macro='edit factionleader'></span></label>
<label>Faction NPC <span macro='edit factionnpc'></span></label>
<label>Allies <span macro='edit factionallies'></span></label>
<label>Opponents <span macro='edit factionopponents'></span></label>
</form>
<form macro='showWhenTagged PC'>
<label>Contacts <span macro='edit contacts'></span></label>
</form>
</div>
<form class='editor'>
<span macro='edit title'></span>
<span macro='edit text'></span>
<span macro='edit tags'></span>
</form>
<div class='tiddlerfooter'>
<span macro='message views.editor.tagPrompt'></span>
<span macro='tagChooser'></span>.
<div macro='annotations'></div>
</div>
<!--}}}-->
!CollapsedTemplate
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::CollapsedToolbar]]'>
<span class='title' macro='view title'></span>
</div>
<!--}}}-->
!PageTemplate
<!--{{{-->
<div class='header'>
<div id='headerSidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<form id='searchForm' macro='search'></form>
<div id='messageArea'></div>
</div>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
</div>
<div id='sidebar'>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='tiddlerDisplay'></div>
</div>
<div id='pageFooter' refresh='content' tiddler='PageFooter'></div>
<!--}}}-->
|''Name''|NPLLTheme|
|''Description''|A theme for the No Place Like London campaign logs|
!Author Mode
|PageTemplate|NPLLTemplates##PageTemplate|
|ViewTemplate|NPLLTemplates##ViewTemplate|
|EditTemplate|NPLLTemplates##EditTemplate|
|StyleSheet|##StyleSheet|
|ColorPalette|##ColorPalette|
!Read-Only Mode
|PageTemplate|NPLLTemplates##PageTemplate|
|ViewTemplate|NPLLTemplates##ViewTemplate|
|EditTemplate|NPLLTemplates##EditTemplate|
|StyleSheet|##StyleSheet|
|ColorPalette|##ColorPalette|
!StyleSheet
/*{{{*/
/* RESET.CSS by Eric Meyer */
/* v1.0 | 20080212 */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
/* remember to define focus styles! */
:focus, :link:focus {
outline: 0;
}
/* remember to highlight inserts somehow! */
ins {
text-decoration: none;
}
del {
text-decoration: line-through;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: collapse;
border-spacing: 0;
}
/* # COLORS # */
body {
background-color:[[ColorPalette::Background]];
color:[[ColorPalette::Foreground]];
}
.tabSelected {color: [[ColorPalette::Foreground]]}
.button, .tabUnselected, #sidebarOptions a, .searchButton {
background-color:[[ColorPalette::Background]];
color:[[ColorPalette::TertiaryDark]];
}
.button:hover, .tabUnselected:hover,
#sidebarOptions a:hover, .searchButton:hover {
color:[[ColorPalette::Foreground]];
}
.tiddlerfooter, #pageFooter, .tiddlersidebar {
color:[[ColorPalette::TertiaryMid]];
}
/* # TYPOGRAPHY # */
body, h1,h2, h3, h4, h5, h6 {
font: 14px/18px Cambria, Georgia, serif;
}
#headerSidebar, #messageArea, .toolbar, .tiddlerfooter, #sidebar, .popup, .popupTiddler, #backstageArea, #backstageButton, .wizard, .tab, .tagged, .tagging, .annotation, #pageFooter, .tiddlersidebar {
font: 12px/18px Calibri, Verdana, sans-serif;
}
.messageToolbar {
font-size: 8px;
line-height: 9px;
}
.viewer pre, .viewer code, textarea {
font: 12px/18px Consolas, Courier New, monospace;
}
input {
font: 12px/16px Consolas, Courier New, monospace; border: 1px solid;
}
textarea {
margin: 8px 0; border: 1px solid;
}
.backstageSelTab, .tabSelected {font-weight: bold;}
/* ## TEXT ALIGNMENT ## */
.toolbar, .messageToolbar {
text-align:right;
}
#mainMenu, .tab, .button, .searchButton, #pageFooter, #sidebarOptions a, .tiddlersidebar, .tiddlerfooter {
text-align: center;
}
/* ## LINKS ## */
a, #sidebarOptions a {text-decoration: none;}
.tiddlyLinkNonExisting {font-style: italic}
.tiddlyLinkExisting {font-style: normal;}
#sidebarTabs .tiddlyLinkNonExisting {font-style: normal}
#sidebarTabs .tiddlyLinkExisting {font-weight: bold;}
.externalLink {text-decoration: underline;}
/* ## HEADERS ## */
h1 {font-size: 24px; line-height: 24px; margin: 6px 3px;}
.backstagePanel .wizard h1, h2 {font-size: 21px; line-height: 24px; margin: 9px 0 3px;}
.backstagePanel .wizard h2, h3 {font-size: 18px; line-height: 21px; margin: 12px 0 3px;}
.backstagePanel .wizard h3, h4, thead, th {font-size: 14px; line-height: 18px; margin: 15px 0 3px;}
.backstagePanel .wizard h4, h5 {font-size: 12px; line-height: 14px; margin: 3px 0 1px;}
.backstagePanel .wizard h5, h6 {font-size: 10px; line-height: 12px; margin: 4px 0 2px;}
.backstagePanel .wizard h6 {font-size: 8px; line-height:10px; margin: 6px 0 2px;}
/* ## TIDDLER SIDEBAR ## */
.tiddlersidebar dt, .tiddlersidebar .listTitle, .tiddlersidebar legend {
font-size: 10px; line-height: 17px; border-bottom: 1px dotted; font-style: normal;
}
.rpgday {
font-size: 48px;
line-height: 1;
}
.rpgyear {
font-size: 18px;
}
.tiddlersidebar input {
line-height: 16px; border: 1px solid; font-size: 11px; width: 60px;
}
/* ## LISTS ## */
li {
margin: 0 0 0 18px;
}
li.listTitle {
font-style: italic;
list-style-type:none;
margin: 0;
}
/* # LAYOUT # */
body {
width: 960px; margin: 0 auto; /* automatic centering */
overflow: auto; /* contains floats */
position: relative;
}
/* ## TIDDLERS ## */
.tiddler {
padding 18px 0;
margin: 18px 0;
overflow: auto;
}
.toolbar { height: 17px; border-bottom-width: 1px; border-style: dotted;}
.toolbar .title {float: left; font-size: 18px; /*font-family: Cambria, Georgia, serif;*/ font-weight: bold; margin: 0 9px;}
.tiddlerfooter {
clear: both;
padding: 4px 0;
margin: 4px 0 5px;
border-top-width: 1px; border-style: dotted;
}
.tiddlersidebar {
width: 62px;
padding: 0 8px 0 9px;
border-right: 1px dotted;
float: left;
display: block;
overflow: hidden;
}
/* ## EDITOR ## */
.editor input {
width: 620px; margin: 0;
}
.editor textarea {
width: 620px;
}
/* ## VIEWER ## */
.viewer, .editor {
float: right;
width: 622px;
padding:9px;
margin:0 0 0 -1px;
border-left: 1px dotted;
}
.viewer pre {
overflow: hidden;
}
.tagging li, .tagged li, .tagging .ul, .tagged li, .tagging .button, .tagged .button{
margin: 0;
clear: none;
}
/* ## POPUPS ## */
.popup, .popupTiddler {
position:absolute; z-index:300; background-color: [[ColorPalette::Background]];
}
.popup li {
margin: 0;
}
.popup {padding: 4px; }
/* ## HEADER ## */
.header {
height: 120px;
overflow: auto; /* contains floats */
}
.siteTitle {
display: block; float: left;
height: 120px; width: 25%;
background: url(./.img/logo.gif) top right no-repeat;
text-indent: -9999999px; /* hides text */
}
#mainMenu{
float: left;
width: 50%;
}
*#mainMenu a {
display: block; float: left;
width: 33%; height: 40px; margin-top: 80px;
font-size:
}
#headerSidebar {
float: right;
width: 25%; height: 120px;
}
#sidebarOptions a, #sidebarOptions .button {
display: block; float: left;
width: 60px; height: 18px; margin: 0;
overflow: hidden;
}
#searchForm {
display: block; clear: both;
overflow: auto;
}
.searchButton {
display: block; float: left;
width: 48px; height: 18px;
}
.searchField {
float: right;
width: 190px; height: 16px; border-width: 1px;
border-style: solid;
line-height: 16px;
}
.messageToolbar {
display: block;
margin-right: 3px;
}
/* ## CONTENT ## */
#displayArea {
margin: 0 240px 0 0;
overflow: visible;
}
/* ### BUTTONS ### */
.button {
height: 18px;
margin: 0 9px;
}
.defaultCommand {
font-weight: bold;
}
.moreCommand {
font-style: italic;
}
.editor .button, #pageFooter .button, .tiddlerfooter .button {
margin: 0;
font-weight: bold;
}
.popup .button { margin: 0; }
/* ### TABS ##*/
.tab:link {}
.tab:hover {}
.tab:active {}
.tab:focus {}
.tabUnselected:link {}
.tabUnselected:hover {}
.tabUnselected:active {}
.tabUnselected:focus {}
.tabSelected:link {}
.tabSelected:hover {}
.tabSelected:active {}
.tabSelected:focus {}
/* ## SIDEBAR ## */
#sidebar {
position:static; float: right;
width: 222px; padding: 0 9px 9px 8px; border-left: 1px dotted;
overflow: visible;
}
#sidebar li {
margin: 0;
}
#sidebarTabs .tabContents {
clear: both;
width: auto;
overflow: hidden;
}
#sidebarTabs .tabset { border-bottom: 1px solid [[ColorPalette::TertiaryMid]]; height: 17px;}
#sidebarTabs .tab {
display: block; float: left;
width: 60px;
margin:0 6px;
border: 1px solid [[ColorPalette::Background]];
border-bottom-color: [[ColorPalette::TertiaryMid]];
height: 16px;
color: [[ColorPalette::Foreground]];
}
#sidebarTabs .tabSelected {
border: 1px solid [[ColorPalette::TertiaryMid]];
border-bottom: 1px solid [[ColorPalette::Background]];
}
#sidebar .tabContents {padding: 9px 8px 8px; border: 1px solid [[ColorPalette::TertiaryMid]]; border-top: none;}
#sidebarTabs .txtMoreTab .tab {
width: 54px;
}
/* ## FOOTER ## */
#pageFooter {
clear: both;
height: auto; width: 100%;
border-top: 1px dotted;
margin: 8px 0 0;
padding-top: 8px;
}
/* # TABLES # */
td, th {
padding: 3px;
}
/* # BACKSTAGE # */
/* ## LAYOUT ## */
#backstageArea {z-index: 100; position:absolute; margin-left: 240px; width: 480px; overflow: hidden;}
#backstageToolbar {padding-left: 9px;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right: 240px; overflow: hidden;}
.backstageTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; left: 240px; top: 18px; width: 462px; margin: 18px 0 0 0; padding: 9px; overflow: hidden;}
.backstagePanelFooter {float:right;}
.backstagePanelFooter a {}
#backstageCloak {display:none; z-index:20; position:absolute; left: 0; top: 0; width:100%; height:100px;}
.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
.wizardFooter {border-top: 1px dotted; padding-top: 8px; margin-top: 9px;}
/* ## TABS ## */
.backstageTab {margin: 0 9px;}
.backstageTab:hover {}
.backstageTab:active {}
.backstageTab:focus {}
.backstageTab.backstageSelTab:hover {}
.backstageTab.backstageSelTab:active {}
.backstageTab.backstageSelTab:focus {}
/* ## COLORS ## */
#backstageArea {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstagePanel {background:[[ColorPalette::Background]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/* # MISC # */
.annotation, .status {font-style: italic;}
/*}}}*/
/***
|Name:|NewMeansNewPlugin|
|Description:|If 'New Tiddler' already exists then create 'New Tiddler (1)' and so on|
|Version:|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
***/
//{{{
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") {
var now = new Date();
title = now.formatString(title.trim());
}
title = config.macros.newTiddler.getName(title); // <--- only changed bit
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");
story.displayTiddler(null,title,template,false,null,null);
var tiddlerElem = document.getElementById(story.idPrefix + 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;
};
//}}}
Male Ogre Giant 4 / Barbarian 2
Rage 2 times/day, 16 rounds (AC ''16'', Attack ''+9'', Damage ''2d8+20'', Vitality ''+12'', Wounds ''+4'', Fort ''13'', Will ''4'')
|statblock|k
|>| //Initiative//| ''<<roll 1d20 '0'>>'' | //AC//| ''18'' |(10 +4 armor +5 racial -1 size) |
|>| //Vitality//| ''72'' | //Touch//| ''9'' |
|>| //Wounds//| ''18'' | //Flat-footed//| ''18'' |
|>|>| ''//Abilities//'' | //Fortitude//| ''<<roll 1d20+11 '11'>>'' |(+7 base +4 con) |
| //Str//| 26 | ''<<roll 1d20+8 '+8'>>'' | //Reflex//| ''<<roll 1d20+1 '1'>>'' |(1 base) |
| //Dex//| 11 | ''<<roll 1d20 '+0'>> '' | //Will//| ''<<roll 1d20+2 '2'>>'' |(1 base 1 wis) |
| //Con//| 18 | ''<<roll 1d20+4 '+4'>>'' |>| ''//Attacks//'' |//Damage// |
| //Int//| 6 | ''<<roll 1d20-2 '-2'>>'' | //Heavy Flail//| ''<<roll 1d20+12 '+12'>>(<<roll 1d20+7 '7'>>)'' |<<roll 2d8+12>>/<<roll 2d8+17>> |
| //Wis//| 12 | ''<<roll 1d20+1 '+1'>>'' | //Unarmed//| ''<<roll 1d20+12 '+12'>>(<<roll 1d20+7 '7'>>)'' |<<roll 1d4+8>>/<<roll 1d4+13>> |
| //Cha//| 4 | ''<<roll 1d20-3 '-3'>>'' | //Grapple//| ''<<roll 1d20+17 '+17'>>'' |
| ''//Skill//''| ''//Stat//'' | ''//Modifier//'' | ''//Ability//'' | ''//Ranks//'' |''//Misc//'' |
| //Intimidate//| Cha | ''<<roll 1d20+9 '9'>>'' | -3 | +9 |+3 (skill focus) |
| //Jump//| Str | ''<<roll 1d20+10 '10'>>'' | +8 ||+4 (speed 40) -2 (armor) |
| //Listen//| Wis | ''<<roll 1d20+1 '1'>>'' | +1 |
| //Spot//| Wis | ''<<roll 1d20+1 '1'>> '' | +1 |
| Feats | Special |h
|Power Attack |Darkvision 60 ft |
|Improved Bull Rush |Rage |
|Skill Focus (Intimidate) |Uncanny Dodge |
Powered by [[TiddlyWiki|http://tiddlywiki.com/]] <<version>>. Design by Martin Andersen. Content © Martin Andersen.
Create a <<newTiddler label:"new chapter" tag:"The Story" tag:"excludeLists" title:"Chapter " focus:"title">> or a <<newTiddler label:"new faction" tag:"factions" tag:"excludeLists" title:"New Faction" focus:"title">
Last updated <<fileDate>>.
Iosef finds several references to [[Nicholas Flamel]], a fourteenth century alchemist. His death has never been reported, and there is no record of his grave. This, along with supposed sightings, has caused old wives' tales and legends of his immortality to grow.
Iosef, however, finds a reference to a letter from Flamel addressed to a certain [[Robert Haversham]]. This letter supposedly contains refinements and perfections to an ancient formula for a '[[rejuvenating potion|Rejuvenating Potion]]' Flamel had discovered. Said ancient formula has been lost. Its last known location was the library at Oxford, from where it was stolen some 300 years ago.
This fund is the not-so-inconspicuous front for the organized [[police|The Police]] corruption.
/***
|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: [
"/*{{{*/",
"/*}}}*/",
""].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();
//}}}
A set of plugins designed to make TiddlyWiki more useful for GMs.
Upon contact, causes ''<<roll 2d6>>'' con damage (DC 35 saves). Next round causes ''<<roll 2d6>>'' con damage (DC 35 saves).
!Delivery methods
* 1 jar (£70), enough for
** 50 Bolts/arrows
** 10 daggers
/***
|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();
//}}}
This ring was stolen from the house of Sir Walthorpe. It is attuned to a ring worn byWalthorpe's sister-in-law, Miss Haversham. Miss Haversham is the youngest daughter of a once-great-but-then-poor-but-now-quite-wealthy family. The [[Haversham family|Haversham Family]] has had a recent influx of wealth from unspecified sources.
Runs [[the Filthy Pig|The Filthy Pig]] for [[the Eye|The Eye]]. Knows [[James|James Norfinwen]] from an unfortunate inident involving a half-orc and an dark alley.
/***
|Name:|SaveCloseTiddlerPlugin|
|Description:|Provides two extra toolbar commands, saveCloseTiddler and cancelCloseTiddler|
|Version:|3.0 ($Rev: 3861 $)|
|Date:|$Date: 2008-03-08 10:53:09 +1000 (Sat, 08 Mar 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(e,src,title) {
config.commands.saveTiddler.handler(e,src,title);
config.commands.closeTiddler.handler(e,src,title);
return false;
}
},
cancelCloseTiddler: {
text: 'cancel/close',
tooltip: 'Undo changes to this tiddler and close it',
handler: function(e,src,title) {
config.commands.cancelTiddler.handler(e,src,title);
config.commands.closeTiddler.handler(e,src,title);
return false;
}
}
});
//}}}
<<newTiddler>><<saveChanges>><<closeAll>>[[RSS|npll.xml]]
<<tabs txtMainTab "All" "All tiddlers" TabAll "Tags" "All tags" TabTags "More" "More lists" TabMore>>
Steampunk in gaslit London
http://draugrheim.net/rpg/npll/
/***
|Name|TabEditPlugin|
|Created by|SaqImtiaz|
|Location|http://tw.lewcid.org/#TabEditPlugin|
|Version|0.32|
|Requires|~TW2.x|
!Description
Makes editing of tabs easier.
!Usage
*Double click a tab to edit the source tiddler
*Double click outside the tabset to edit the containing tiddler.
!Demo
TestTabs
!History
*28-04-06, v0.32 - fixed previous bug fix!
*27-04-06, v0.31 - fixed conflicts with tabs created using PartTiddler.
*26-04-06, v0.30 - first public release
***/
//{{{
//tab on double click event handler
Story.prototype.onTabDblClick = function(e){
if (!e) var e = window.event;
var theTarget = resolveTarget(e);
var title= this.getAttribute("source");
if ((version.extensions.PartTiddlerPlugin)&&(title.indexOf("/")!=-1))
{if (!oldFetchTiddler.call(this, [title]))
{return false;}}
story.displayTiddler(theTarget,title,2,false,null)
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
return false;
}
config.macros.tabs.switchTab = function(tabset,tab)
{
var cookie = tabset.getAttribute("cookie");
var theTab = null
var nodes = tabset.childNodes;
for(var t=0; t<nodes.length; t++)
if(nodes[t].getAttribute && nodes[t].getAttribute("tab") == tab)
{
theTab = nodes[t];
theTab.className = "tab tabSelected";
}
else
nodes[t].className = "tab tabUnselected"
if(theTab)
{
if(tabset.nextSibling && tabset.nextSibling.className == "tabContents")
tabset.parentNode.removeChild(tabset.nextSibling);
var tabContent = createTiddlyElement(null,"div",null,"tabContents",null);
tabset.parentNode.insertBefore(tabContent,tabset.nextSibling);
var contentTitle = theTab.getAttribute("content");
//set source attribute equal to title of tiddler displayed in tab
tabContent.setAttribute("source",contentTitle);
//add dbl click event
tabContent.ondblclick = story.onTabDblClick;
wikify(store.getTiddlerText(contentTitle),tabContent,null,store.getTiddler(contentTitle));
if(cookie)
{
config.options[cookie] = tab;
saveOptionCookie(cookie);
}
}
}
//}}}
<<tabs txtMoreTab "Missing" "Missing tiddlers" TabMoreMissing "Orphans" "Orphaned tiddlers" TabMoreOrphans "Shadowed" "Shadowed tiddlers" TabMoreShadowed>>
/***
|''Name:''|TableSortingPlugin|
|''Description:''|Dynamically sort tables by clicking on column headers|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Source:''|http://tw.lewcid.org/#TableSortingPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|2.02|
|''Date:''|25-01-2008|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|
!!Usage:
* Make sure your table has a header row
** {{{|Name|Phone Number|Address|h}}}<br> Note the /h/ that denote a header row
* Give the table a class of 'sortable'
** {{{
|sortable|k
|Name|Phone Number|Address|h
}}}<br>Note the /k/ that denotes a class name being assigned to the table.
* To disallow sorting by a column, place {{{<<nosort>>}}} in it's header
* To automatically sort a table by a column, place {{{<<autosort>>}}} in the header for that column
** Or to sort automatically but in reverse order, use {{{<<autosort reverse>>}}}
!!Example:
|sortable|k
|Name |Salary |Extension |Performance |File Size |Start date |h
|ZBloggs, Fred |$12000.00 |1353 |+1.2 |74.2Kb |Aug 19, 2003 21:34:00 |
|ABloggs, Fred |$12000.00 |1353 |1.2 |3350b |09/18/2003 |
|CBloggs, Fred |$12000 |1353 |1.200 |55.2Kb |August 18, 2003 |
|DBloggs, Fred |$12000.00 |1353 |1.2 |2100b |07/18/2003 |
|Bloggs, Fred |$12000.00 |1353 |01.20 |6.156Mb |08/17/2003 05:43 |
|Turvey, Kevin |$191200.00 |2342 |-33 |1b |02/05/1979 |
|Mbogo, Arnold |$32010.12 |2755 |-21.673 |1.2Gb |09/08/1998 |
|Shakespeare, Bill |£122000.00|3211 |6 |33.22Gb |12/11/1961 |
|Shakespeare, Hamlet |£9000 |9005 |-8 |3Gb |01/01/2002 |
|Fitz, Marvin |€3300.30 |5554 |+5 |4Kb |05/22/1995 |
***/
// /%
//!BEGIN-PLUGIN-CODE
config.tableSorting = {
darrow: "\u2193",
uarrow: "\u2191",
getText : function (o) {
var p = o.cells[SORT_INDEX];
return p.innerText || p.textContent || '';
},
sortTable : function (o,rev) {
SORT_INDEX = o.getAttribute("index");
var c = config.tableSorting;
var T = findRelated(o.parentNode,"TABLE");
if(T.tBodies[0].rows.length<=1)
return;
var itm = "";
var i = 0;
while (itm == "" && i < T.tBodies[0].rows.length) {
itm = c.getText(T.tBodies[0].rows[i]).trim();
i++;
}
if (itm == "")
return;
var r = [];
var S = o.getElementsByTagName("span")[0];
c.fn = c.sortAlpha;
if(!isNaN(Date.parse(itm)))
c.fn = c.sortDate;
else if(itm.match(/^[$|£|€|\+|\-]{0,1}\d*\.{0,1}\d+$/))
c.fn = c.sortNumber;
else if(itm.match(/^\d*\.{0,1}\d+[K|M|G]{0,1}b$/))
c.fn = c.sortFile;
for(i=0; i<T.tBodies[0].rows.length; i++) {
r[i]=T.tBodies[0].rows[i];
}
r.sort(c.reSort);
if(S.firstChild.nodeValue==c.darrow || rev) {
r.reverse();
S.firstChild.nodeValue=c.uarrow;
}
else
S.firstChild.nodeValue=c.darrow;
var thead = T.getElementsByTagName('thead')[0];
var headers = thead.rows[thead.rows.length-1].cells;
for(var k=0; k<headers.length; k++) {
if(!hasClass(headers[k],"nosort"))
addClass(headers[k].getElementsByTagName("span")[0],"hidden");
}
removeClass(S,"hidden");
for(i=0; i<r.length; i++) {
T.tBodies[0].appendChild(r[i]);
c.stripe(r[i],i);
for(var j=0; j<r[i].cells.length;j++){
removeClass(r[i].cells[j],"sortedCol");
}
addClass(r[i].cells[SORT_INDEX],"sortedCol");
}
},
stripe : function (e,i){
var cl = ["oddRow","evenRow"];
i&1? cl.reverse() : cl;
removeClass(e,cl[1]);
addClass(e,cl[0]);
},
sortNumber : function(v) {
var x = parseFloat(this.getText(v).replace(/[^0-9.-]/g,''));
return isNaN(x)? 0: x;
},
sortDate : function(v) {
return Date.parse(this.getText(v));
},
sortAlpha : function(v) {
return this.getText(v).toLowerCase();
},
sortFile : function(v) {
var j, q = config.messages.sizeTemplates, s = this.getText(v);
for (var i=0; i<q.length; i++) {
if ((j = s.toLowerCase().indexOf(q[i].template.replace("%0\u00a0","").toLowerCase())) != -1)
return q[i].unit * s.substr(0,j);
}
return parseFloat(s);
},
reSort : function(a,b){
var c = config.tableSorting;
var aa = c.fn(a);
var bb = c.fn(b);
return ((aa==bb)? 0 : ((aa<bb)? -1:1));
}
};
Story.prototype.tSort_refreshTiddler = Story.prototype.refreshTiddler;
Story.prototype.refreshTiddler = function(title,template,force,customFields,defaultText){
var elem = this.tSort_refreshTiddler.apply(this,arguments);
if(elem){
var tables = elem.getElementsByTagName("TABLE");
var c = config.tableSorting;
for(var i=0; i<tables.length; i++){
if(hasClass(tables[i],"sortable")){
var x = null, rev, table = tables[i], thead = table.getElementsByTagName('thead')[0], headers = thead.rows[thead.rows.length-1].cells;
for (var j=0; j<headers.length; j++){
var h = headers[j];
if (hasClass(h,"nosort"))
continue;
h.setAttribute("index",j);
h.onclick = function(){c.sortTable(this); return false;};
h.ondblclick = stopEvent;
if(h.getElementsByTagName("span").length == 0)
createTiddlyElement(h,"span",null,"hidden",c.uarrow);
if(!x && hasClass(h,"autosort")) {
x = j;
rev = hasClass(h,"reverse");
}
}
if(x)
c.sortTable(headers[x],rev);
}
}
}
return elem;
};
setStylesheet("table.sortable span.hidden {visibility:hidden;}\n"+
"table.sortable thead {cursor:pointer;}\n"+
"table.sortable .nosort {cursor:default;}\n"+
"table.sortable td.sortedCol {background:#ffc;}","TableSortingPluginStyles");
function stopEvent(e){
var ev = e? e : window.event;
ev.cancelBubble = true;
if (ev.stopPropagation) ev.stopPropagation();
return false;
}
config.macros.nosort={
handler : function(place){
addClass(place,"nosort");
}
};
config.macros.autosort={
handler : function(place,m,p,w,pS){
addClass(place,"autosort"+" "+pS);
}
};
//!END-PLUGIN-CODE
// %/
A seedy bar in one of the more shady areas of London. If a dirty job needs doing, chances are one of the patrons is willing.
In London, the Cabal is searching for ways to regain it's lost glory.
[[Iosef Tesla]] - Enchanter wizard (mind controller)
[[James Norfinwen]] - Half-elven Swashbuckler (James' butler)
[[Cassie]] - Human swashbuckler (Trained airship captain)
[[Hans König]] - Human Rogue
[[Percival]] - Half-Ogre fighter
!!London
<<tiddler London>>
!!Factions
<<forEachTiddler
where
'tiddler.tags.contains("Faction")'
write
'"!!![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
!!Places
<<forEachTiddler
where
'tiddler.tags.contains("Places")'
write
'"!!![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
!!People
<<forEachTiddler
where
'tiddler.tags.contains("NPC")'
write
'"!!![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
The Dwarven Council is the governing body for the dwarves living in England (although these dwarves formally are considered to be under English law, jurisdiction is handed over to the dwarves almost every time a dwarf is involved in a legal dispute).
The Council also controls considerable political power - the lack of dwarven engineers, guards and brewers on missions of exploration, dwarven builders on constriction projects, or dwarven gold to back up investments can make or break any businessman with an idea.
The Eye has its global power center in London, and has the greatest influence on shady deals in the city. The Eye's main rival is [[the Hand|The Hand]].
Where James arranges lodging for Tesla's employees in shady ventures. Fronts as a very cheap brothel, but really is an opium den. It is run by [[The Eye]].
The Council is formed by the most successful merchants and industrialists in (or based in) London. [[The police|The Police]] is firmly in their pockets, as are goverment officials in convenient places such as toll offices, docks, and other points of entry into London.
The Hand's foothold in London is tenuous at best. It has gained some level of control of the docks, to the Eye's great discomfort.
The Immortal (so called because he does not seem to die - or even age, for that matter) is the person to go to if you need shavings of a unicorn horn, the blood of a virgin, a goat's musk, or any other little item that is useful in the practice of magic.
Fiercely independent, he has sworn off the Cabal. There are rumors that he once was a prominent member. His uncanny knack for filling the varied needs of magicians earns him some respect, along with the myths and mysteries that surround his age and appearance.
Corrupt, but not incompetent, the London City Police is very nearly a crime syndicate in it's own right. Controlled by the city's [[governing council|The Governing Council]], the police force is more or less the personal guard of the mercantile and industrial elite.
<<forEachTiddler
where
'tiddler.tags.contains("The Police")'
write
'"!![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
<<forEachTiddler
where
'tiddler.tags.contains("The Story")'
sortBy
'(tiddler.title.toLowerCase())'
write
'"![["+tiddler.title+"]]\n<<tiddler [["+tiddler.title+"]]$))\n"'
>>
Gaia, late 19th century. A relatively stable political climate in Europe has led to a period of prosperity. The [[elves|Elves]] lament the corruption of nature and magic by steam-spewing, coal-eating engines, while the [[dwarwes|Dwarves]] revel in the new markets for coal, engines, weapons and mercenaries.
Industrialization has brought along considerable advances to the humans of Europe. [[The Cabal]] laments this course in human history - they wish to continue to sell their services as mages dearly.
The lesser races - the [[Exotics]] that are discovered in Africa, India, the Americas are readily overpowered and enslaved by the europeans. Their primitive, ritualistic magic is - wih few exceptions - no match for guns forged from dwarwen steel.
The recent industrialization of Europe is largely due to the [[Dwarves]] teaching humans. The dwarves needed new markets for coal, iron, guns and war machines.
|''Type:''|file|
|''URL:''|http://www.tiddlytools.com/|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
|''Type:''|file|
|''URL:''|http://tiddlywiki.com|
|''Workspace:''|(default)|
This tiddler was automatically created to record the details of this server
|~CollapsedToolbar|+expandTiddler collapseOthers closeTiddler closeOthers > permalink jump|
|~ViewToolbar|collapseTiddler collapseOthers closeTiddler closeOthers +editTiddler > fields syncing permalink references jump|
|~EditToolbar|collapseOthers +saveTiddler -cancelTiddler deleteTiddler > fields references jump|
On the subject of taking over another body, Iosef finds very little. [[Soulsharing]] is mentioned, where two consciousnesses occupy the same (willing) mind. This process is not without risk, and not viable for extended periods of time. There is also mention of the extraction of lifeforces from other beings to bolster one's own temporarily.
* At sign of danger, [[lookouts|Human Guards]] alert [[dwarves]], take cover, softens attacker
* Dwarves goad ogre
* Mooks come out of buildings (roof, door) after 20-30 rounds (lone guard inside sends for reinforcements), taking cover -> firefight
!Small warehouse
Weapons stash containing
!!Ammunition (2 boxes are magic (increased critical/+3)
* 12-gauge shotgun shells x2 (10 x 20)
* 18-gauge shotgun shells x1 (10 x 15)
* .45 rounds x1 (10 x 50)
* .30 rounds x1 (10 x 50)
!!Weapons
* 1 crate w/50 handguns ([[Colt Peacemaker]] knockoff - 4 magic - wounding)
* 1 crate w/20 shotguns ([[12-gauge Double Barrel Shotgun]] - 1 magic (fiery burst) )
* 1 small crate w/5 large-sized shotguns ([[18-gauge Double Barrel Shotgun]] - 1 magic (fiery burst))
* 1 small crate w/5 rifles ([[Winchester 1873 Rifle]] knockoff - 1 magic (double range, +1))
!!Explosives
* 1 box dynamite (20 sticks)
* 1 box w/ 30 grenades (all magic - 10x+2d6 fire, 10xcone of silence, 10xdemonsbane)
!Large Warehouse
Upon inhalation, causes ''<<roll 1d4>>'' con damage (DC 24 saves). Next round causes ''<<roll 2d6>>'' con damage (DC 24 saves). The poison disperses after 1d4 rounds.
!Delivery methods
* Glass bottle (£60)
* Grenade, 10 ft radius (£80)
* Grenade, 15 ft radius (£100)
|Damage|2d6|
|Range|50ft|
/***
|''Name:''|fileDate|
|''Version:''|Revision: 1.0.1, 2006-04-20|
|''Source:''|http://knighjm.googlepages.com/knightnet-default-tw.html#fileDate|
|''Author:''|[[Julian Knight]]|
|''Type:''|Plugin|
|''Requires:''|TiddlyWiki 2.0.0 or higher|
!Description
Returns the date/time that the current TiddlyWiki file was saved.
!History
|!2006-04-20 - 1.0.1|Update default format to include leading zeros|
|!2006-04-20 - 1.0.0|First release, thanks to [[Eric Shulman|http://www.TiddlyTools.com]] for the starting code. See his DatePlugin for a comprehensive date plugin|
!Usage
<<fileDate "DateFormatString">>
Where "DateFormatString" is optional and formats the output - default format is "YYYY-MM-DD hh:mm".
!Code
***/
//{{{
version.extensions.fileDate = {
major: 1, minor: 0, revision: 1, date: new Date("Apr 20, 2006"), type: 'macro',
source: 'http://knighjm.googlepages.com/knightnet-default-tw.html#fileDate'
};
config.macros.fileDate = {
defaultFmt: "YYYY-0MM-0DD 0hh:0mm"
};
config.macros.fileDate.handler = function(place,macroName,params,wikifier,paramString,callingTiddler) {
var format=params[0];
if (!format)
format=config.macros.fileDate.defaultFmt;
wikify((new Date(document.lastModified)).formatString(format),place);
}
//}}}
/***
This plugin is released under the "Do whatever you like at your own risk" license.
***/