PageTemplate\nModified ViewTemplate\n* {{{<div class="tagglyTagged" macro="tags"></div>}}}\n* {{{<div class="singleTiddlerContainer">}}}\n* removed created date\nStyleSheet\n
<<list shadowed>>
/***\n! Style Sheet: Clean Green\n|''Style Sheet Name:''|Clean Green|\n|''Version:''|1.0 FIREFOX ONLY (2006-01-29)|\n|''Source:''|http://www.tentacle.net/~psifi/tiddlytracks/#CleanGreenStyleSheet|\n|''Author:''|Christine Hodges (see Google Groups)|\n|''Tiddlers Required:''|PageTemplate, ViewTemplate (see AboutStyles)|\n|''TiddlyWiki:''|2.0|\n|''Browsers:''|Firefox only for now. Bah.|\n\n!Header /%==================================================%/\n***/\n/*{{{*/\n.header\n{\n clear: both;\n background: #707c51;\n color: #CCff99;\n font-family: trebuchet ms, veranda, georgia;\n}\n\n.headerForeground\n{\n color: #cadeb9;\n position: relative;\n padding: 2em 0em 1em 1em;\n}\n\n.headerForeground a\n{\n color: #cadeb9;\n}\n\n.siteTitle { font-weight: bold; font-size: 3em; }\n.siteSubtitle { font-weight: normal; font-size: 1.3em; }\n/*}}}*/\n\n/***\n!Horizontal Main Menu /%=====================================%/\nTop menu is based on MPTW (http://simonbaird.com/mptw/).\n***/\n/*{{{*/\n#topMenu\n{\n background: #fff;\n padding: 2px;\n}\n\n#topMenu .button, #topMenu .tiddlyLink\n{\n color: #333;\n font-weight: bold;\n font-size: 1.1em;\n text-decoration: none;\n letter-spacing: 1.5px;\n}\n\n#topMenu br { display: none; }\n \n#topMenu ul\n{\n /*float: right;*/\n right: 0; /* http://www.communitymx.com/content/article.cfm?cid=529B0 */\n padding: 0;\n margin: 0px 0px 15px 0px;\n list-style: none;\n}\n\n#topMenu ul li a {\n display: block;\n float: left;\n background: #cadeb9;\n padding: 5px 15px 5px 15px;\n margin: 2px 2px 2px 2px;\n text-align: center;\n}\n\n#topMenu ul li a:hover {\n color: #666600;\n border: 2px solid #666600;\n}\n\n#topMenu .button:hover { border: 2px solid #7CAF6B; }\n#displayArea { margin: 1em 15.7em 0em 1em; }\n\n/* so we use the freed up space */\n/* just in case want some QuickOpenTags in your topMenu */\n#topMenu .quickopentag\n{\n padding: 0px;\n margin: 0px;\n border: 0px;\n}\n\n#topMenu .quickopentag .tiddlyLink\n{\n padding-right: 1px;\n margin-right: 0px;\n}\n\n#topMenu .quickopentag .button\n{\n padding-left: 1px;\n margin-left: 0px;\n border: 0px;\n}\n\n/*}}}*/\n\n/***\n!General /%==================================================%/\n***/\n/*{{{*/\nh1 {\n color: #333;\n background: #cadeb9;\n padding: 2px;\n}\n\nh2 {\n color: #707c51;\n background: #fff;\n border-bottom: 2px dotted #cadeb9;\n padding: 2px;\n}\n\nh3 {\n color: #707c51;\n background: #fff;\n border-bottom: 1px dotted #cadeb9;\n padding: 2px;\n}\n\nh4, h5 {\n color: #707c51;\n background: #fff;\n padding: 1.5px;\n}\n\na{\n color: #666600; /* #707c51; */\n}\n\na:hover{\n background: #666600;\n color: #fff;\n}\n\n.button {\n color: #014;\n border: 1px solid #fff;\n}\n\n.button:hover {\n color: #014;\n background: #cadeb9;\n border: 1px solid #707c51;\n}\n\n.button:active {\n color: #fff;\n background: #707c51;\n border: 1px solid #333;\n}\n/*}}}*/\n\n/***\n!Tiddler and Task Tiddler Display /%========================================%/\n***/\n/*{{{*/\n.singleTiddlerContainer {\n border: 2px dashed #ccc;\n margin: 0px -10px 0px -10px;\n padding: 10px;\n/* for .tiddler: margin: 25px 5px 5px 0px; padding: 15px 10px 10px 10px; */\n}\n\n#ttTaskContainer {\n border: 2px dashed #cadeb9;\n margin: 0px -10px 0px -10px;\n padding: 10px 10px 10px 10px;\n}\n\n#ttTaskTitle {\n color: #333;\n font-weight: bold;\n font-family: georgia;\n}\n\n#ttTaskTitle .title {\n font-size: 1em;\n}\n\ndiv.ttTaskListText:hover {\n background: #fe8;\n}\n\n.ttTaskListText { /* filling cell */\n margin: -5px -2px -5px -2px;\n padding: 5px 3px 5px 3px;\n}\n\n.tagglyTagged li.listTitle { display:none;}\n.tagglyTagged li { display: inline; font-size:90%; }\n.tagglyTagged ul { margin:0px; padding:0px; }\n\n.tagging { float: none; width:40%; }\n\n#tiddlerDisplay { padding-bottom: 5px; }\n\n#tiddlerDisplay .title {\n color: #333;\n margin-bottom: 2px;\n margin-left: -3px;\n font-weight: bold;\n font-family: georgia;\n letter-spacing: 0.5px;\n}\n\n\n.subtitle {\n float: right;\n color: #866;\n margin-top: 5px;\n}\n/*}}}*/
/***\n<html>\n<input type="submit" value="X"\nonclick="testClick(event)" tiddler="testTiddler" \nstyle="color:#660000; padding: 0;\n font-family:Arial Black;\n background-color:#fff;\n border:1px solid;\n border-color:#660000;" /></html>\n\n***/\n//{{{\nfunction testClick(e) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n alert(target.getAttribute("tiddler", "bah!"));\n return false;\n}\n\n//}}}
/***\nLine feeds do take up space tho.\n\n***/\n//{{{\nconfig.macros.comment= {\n label: "comment",\n prompt: "Add a comment only viewable in edit mode.",\n handler: function(place,macroName,params) { }\n};\n\n\n//}}}
/***\n|''Name:''|DataTiddlerPlugin|\n|''Version:''|1.0.3 (2006-01-06)|\n|''Source:''|http://tiddlywiki.abego-software.de/#DataTiddlerPlugin|\n|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|\n|''Licence:''|[[BSD open source license]]|\n|''TiddlyWiki:''|1.2.38+, 2.0|\n|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|\n!Description\nEnhance 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).\n\nSuch tiddler data can be used in various applications. E.g. you may create tables that collect data from various tiddlers. \n\n''//Example: "Table with all December Expenses"//''\n{{{\n<<forEachTiddler\n where\n 'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'\n write\n '"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\sn"'\n>>\n}}}\n//(This assumes that expenses are stored in tiddlers tagged with "expense".)//\n<<forEachTiddler\n where\n 'tiddler.tags.contains("expense") && tiddler.data("month") == "Dec"'\n write\n '"|[["+tiddler.title+"]]|"+tiddler.data("descr")+"| "+tiddler.data("amount")+"|\sn"'\n>>\nFor other examples see DataTiddlerExamples.\n\n\n\n\n''Access and Modify Tiddler Data''\n\nYou 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. \n\nThese values can be accessed and modified through the following Tiddler methods:\n|!Method|!Example|!Description|\n|{{{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.|\n|{{{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.|\n|{{{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.|\n|{{{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.|\n|{{{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).|\n\nAlternatively 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.\n|!Method|!Description|\n|{{{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.|\n|{{{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.|\n|{{{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.|\n|{{{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.|\n|{{{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).|\n//(For details on the various functions see the detailed comments in the source code.)//\n\n\n''Data Representation in a Tiddler''\n\nThe 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]]. \n\n//''Data Section Example:''//\n{{{\n<data>{"isVIP":true,"user":"John Brown","age":34}</data>\n}}}\n\nThe data section is not displayed when viewing the tiddler (see also "The showData Macro").\n\nBeside the data section a tiddler may have all kind of other content.\n\nTypically 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.\n\n\n''Saving Changes''\n\nThe "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.\n\n\n''Notifications''\n\nNo notifications are sent when a tiddler's data value is changed through the "setData" methods. \n\n''Escape Data Section''\nIn 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>}}}.\n\n\n''The showData Macro''\n\nBy 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:\n\n''Syntax:'' \n|>|{{{<<}}}''showData '' [''JSON''] [//tiddlerName//] {{{>>}}}|\n|''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|\n|//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.)|\n|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|\n\n\n!Revision history\n* v1.0.3 (2006-01-06)\n** Support TiddlyWiki 2.0\n* v1.0.2 (2005-12-22)\n** Enhancements:\n*** Handle texts "<data>" or "</data>" more robust when used in a tiddler text or as a field value.\n*** Improved (JSON) error messages.\n** Bugs fixed: \n*** References are not updated when using the DataTiddler.\n*** Changes to compound objects are not always saved.\n*** "~</data>" is not rendered correctly (expected "</data>")\n* v1.0.1 (2005-12-13)\n** Features: \n*** The showData macro supports an optional "tiddlername" argument to specify the tiddler containing the data to be displayed\n** Bugs fixed: \n*** A script immediately following a data section is deleted when the data is changed. (Thanks to GeoffS for reporting.)\n* v1.0.0 (2005-12-12)\n** initial version\n\n!Code\n***/\n//{{{\n//============================================================================\n//============================================================================\n// DataTiddlerPlugin\n//============================================================================\n//============================================================================\n\n// Ensure that the DataTiddler Plugin is only installed once.\n//\nif (!version.extensions.DataTiddlerPlugin) {\n\n\n\nversion.extensions.DataTiddlerPlugin = {\n major: 1, minor: 0, revision: 3,\n date: new Date(2006, 1, 6), \n type: 'plugin',\n source: "http://tiddlywiki.abego-software.de/#DataTiddlerPlugin"\n};\n\n// For backward compatibility with v1.2.x\n//\nif (!window.story) window.story=window; \nif (!TiddlyWiki.prototype.getTiddler) TiddlyWiki.prototype.getTiddler = function(title) { return t = this.tiddlers[title]; return (t != undefined && t instanceof Tiddler) ? t : null; } \n\n//============================================================================\n// DataTiddler Class\n//============================================================================\n\n// ---------------------------------------------------------------------------\n// Configurations and constants \n// ---------------------------------------------------------------------------\n\nfunction DataTiddler() {\n}\n\nDataTiddler = {\n // Function to stringify a JavaScript value, producing the text for the data section content.\n // (Must match the implementation of DataTiddler.parse.)\n //\n stringify : null,\n \n\n // Function to parse the text for the data section content, producing a JavaScript value.\n // (Must match the implementation of DataTiddler.stringify.)\n //\n parse : null\n};\n\n// Ensure access for IE\nwindow.DataTiddler = DataTiddler;\n\n// ---------------------------------------------------------------------------\n// Data Accessor and Mutator\n// ---------------------------------------------------------------------------\n\n\n// Returns the value of the given data field of the tiddler.\n// When no such field is defined or its value is undefined\n// the defaultValue is returned.\n// \n// @param tiddler either a tiddler name or a tiddler\n//\nDataTiddler.getData = function(tiddler, field, defaultValue) {\n var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;\n if (!(t instanceof Tiddler)) {\n throw "Tiddler expected. Got "+tiddler;\n }\n\n return DataTiddler.getTiddlerDataValue(t, field, defaultValue);\n}\n\n\n// Sets the value of the given data field of the tiddler to\n// the value. When the value is equal to the defaultValue\n// no value is set (and the field is removed)\n//\n// Changing data of a tiddler will not trigger notifications.\n// \n// @param tiddler either a tiddler name or a tiddler\n//\nDataTiddler.setData = function(tiddler, field, value, defaultValue) {\n var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;\n if (!(t instanceof Tiddler)) {\n throw "Tiddler expected. Got "+tiddler+ "("+t+")";\n }\n\n DataTiddler.setTiddlerDataValue(t, field, value, defaultValue);\n}\n\n\n// Returns the data object of the tiddler, with a property for every field.\n//\n// The properties of the returned data object may only be read and\n// not be modified. To modify the data use DataTiddler.setData(...) \n// or the corresponding Tiddler method.\n//\n// If no data section is defined a new (empty) object is returned.\n//\n// @param tiddler either a tiddler name or a Tiddler\n//\nDataTiddler.getDataObject = function(tiddler) {\n var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;\n if (!(t instanceof Tiddler)) {\n throw "Tiddler expected. Got "+tiddler;\n }\n\n return DataTiddler.getTiddlerDataObject(t);\n}\n\n// Returns the text of the content of the data section of the tiddler.\n//\n// When no data section is defined for the tiddler null is returned \n//\n// @param tiddler either a tiddler name or a Tiddler\n// @return [may be null]\n//\nDataTiddler.getDataText = function(tiddler) {\n var t = (typeof tiddler == "string") ? store.getTiddler(tiddler) : tiddler;\n if (!(t instanceof Tiddler)) {\n throw "Tiddler expected. Got "+tiddler;\n }\n\n return DataTiddler.readDataSectionText(t);\n}\n\n\n// ---------------------------------------------------------------------------\n// Internal helper methods (must not be used by code from outside this plugin)\n// ---------------------------------------------------------------------------\n\n// Internal.\n//\n// The original JSONError is not very user friendly, \n// especially it does not define a toString() method\n// Therefore we extend it here.\n//\nDataTiddler.extendJSONError = function(ex) {\n if (ex.name == 'JSONError') {\n ex.toString = function() {\n return ex.name + ": "+ex.message+" ("+ex.text+")";\n }\n }\n return ex;\n}\n\n// Internal.\n//\n// @param t a Tiddler\n//\nDataTiddler.getTiddlerDataObject = function(t) {\n if (t.dataObject == undefined) {\n var data = DataTiddler.readData(t);\n t.dataObject = (data) ? data : {};\n }\n \n return t.dataObject;\n}\n\n\n// Internal.\n//\n// @param tiddler a Tiddler\n//\nDataTiddler.getTiddlerDataValue = function(tiddler, field, defaultValue) {\n var value = DataTiddler.getTiddlerDataObject(tiddler)[field];\n return (value == undefined) ? defaultValue : value;\n}\n\n\n// Internal.\n//\n// @param tiddler a Tiddler\n//\nDataTiddler.setTiddlerDataValue = function(tiddler, field, value, defaultValue) {\n var data = DataTiddler.getTiddlerDataObject(tiddler);\n var oldValue = data[field];\n \n if (value == defaultValue) {\n if (oldValue != undefined) {\n delete data[field];\n DataTiddler.save(tiddler);\n }\n return;\n }\n data[field] = value;\n DataTiddler.save(tiddler);\n}\n\n// Internal.\n//\n// Reads the data section from the tiddler's content and returns its text\n// (as a String).\n//\n// Returns null when no data is defined.\n//\n// @param tiddler a Tiddler\n// @return [may be null]\n//\nDataTiddler.readDataSectionText = function(tiddler) {\n var matches = DataTiddler.getDataTiddlerMatches(tiddler);\n if (matches == null || !matches[2]) {\n return null;\n }\n return matches[2];\n}\n\n// Internal.\n//\n// Reads the data section from the tiddler's content and returns it\n// (as an internalized object).\n//\n// Returns null when no data is defined.\n//\n// @param tiddler a Tiddler\n// @return [may be null]\n//\nDataTiddler.readData = function(tiddler) {\n var text = DataTiddler.readDataSectionText(tiddler);\n try {\n return text ? DataTiddler.parse(text) : null;\n } catch(ex) {\n throw DataTiddler.extendJSONError(ex);\n }\n}\n\n// Internal.\n// \n// Returns the serialized text of the data of the given tiddler, as it\n// should be stored in the data section.\n//\n// @param tiddler a Tiddler\n//\nDataTiddler.getDataTextOfTiddler = function(tiddler) {\n var data = DataTiddler.getTiddlerDataObject(tiddler);\n return DataTiddler.stringify(data);\n}\n\n\n// Internal.\n// \nDataTiddler.indexOfNonEscapedText = function(s, subString, startIndex) {\n var index = s.indexOf(subString, startIndex);\n while ((index > 0) && (s[index-1] == '~')) { \n index = s.indexOf(subString, index+1);\n }\n return index;\n}\n\n// Internal.\n//\nDataTiddler.getDataSectionInfo = function(text) {\n // Special care must be taken to handle "<data>" and "</data>" texts inside\n // a data section. \n // Also take care not to use an escaped <data> (i.e. "~<data>") as the start \n // of a data section. (Same for </data>)\n\n // NOTE: we are explicitly searching for a data section that contains a JSON\n // string, i.e. framed with braces. This way we are little bit more robust in\n // case the tiddler contains unescaped texts "<data>" or "</data>". This must\n // be changed when using a different stringifier.\n\n var startTagText = "<data>{";\n var endTagText = "}</data>";\n\n var startPos = 0;\n\n // Find the first not escaped "<data>".\n var startDataTagIndex = DataTiddler.indexOfNonEscapedText(text, startTagText, 0);\n if (startDataTagIndex < 0) {\n return null;\n }\n\n // Find the *last* not escaped "</data>".\n var endDataTagIndex = text.indexOf(endTagText, startDataTagIndex);\n if (endDataTagIndex < 0) {\n return null;\n }\n var nextEndDataTagIndex;\n while ((nextEndDataTagIndex = text.indexOf(endTagText, endDataTagIndex+1)) >= 0) {\n endDataTagIndex = nextEndDataTagIndex;\n };\n\n return {\n prefixEnd: startDataTagIndex, \n dataStart: startDataTagIndex+(startTagText.length)-1, \n dataEnd: endDataTagIndex, \n suffixStart: endDataTagIndex+(endTagText.length)\n };\n}\n\n// Internal.\n// \n// Returns the "matches" of a content of a DataTiddler on the\n// "data" regular expression. Return null when no data is defined\n// in the tiddler content.\n//\n// Group 1: text before data section (prefix)\n// Group 2: content of data section\n// Group 3: text behind data section (suffix)\n//\n// @param tiddler a Tiddler\n// @return [may be null] null when the tiddler contains no data section, otherwise see above.\n//\nDataTiddler.getDataTiddlerMatches = function(tiddler) {\n var text = tiddler.text;\n var info = DataTiddler.getDataSectionInfo(text);\n if (!info) {\n return null;\n }\n\n var prefix = text.substr(0,info.prefixEnd);\n var data = text.substr(info.dataStart, info.dataEnd-info.dataStart+1);\n var suffix = text.substr(info.suffixStart);\n \n return [text, prefix, data, suffix];\n}\n\n\n// Internal.\n//\n// Saves the data in a <data> block of the given tiddler (as a minor change). \n//\n// The "chkAutoSave" and "chkForceMinorUpdate" options are respected. \n// I.e. the TiddlyWiki *file* is only saved when AutoSave is on.\n//\n// Notifications are not send. \n//\n// This method should only be called when the data really has changed. \n//\n// @param tiddler\n// the tiddler to be saved.\n//\nDataTiddler.save = function(tiddler) {\n\n var matches = DataTiddler.getDataTiddlerMatches(tiddler);\n\n var prefix;\n var suffix;\n if (matches == null) {\n prefix = tiddler.text;\n suffix = "";\n } else {\n prefix = matches[1];\n suffix = matches[3];\n }\n\n var dataText = DataTiddler.getDataTextOfTiddler(tiddler);\n var newText = \n (dataText != null) \n ? prefix + "<data>" + dataText + "</data>" + suffix\n : prefix + suffix;\n if (newText != tiddler.text) {\n // make the change in the tiddlers text\n \n // ... see DataTiddler.MyTiddlerChangedFunction\n tiddler.isDataTiddlerChange = true;\n \n // ... do the action change\n tiddler.set(\n tiddler.title,\n newText,\n config.options.txtUserName, \n config.options.chkForceMinorUpdate? undefined : new Date(),\n tiddler.tags);\n\n // ... see DataTiddler.MyTiddlerChangedFunction\n delete tiddler.isDataTiddlerChange;\n\n // Mark the store as dirty.\n store.dirty = true;\n \n // AutoSave if option is selected\n if(config.options.chkAutoSave) {\n saveChanges();\n }\n }\n}\n\n// Internal.\n//\nDataTiddler.MyTiddlerChangedFunction = function() {\n // Remove the data object from the tiddler when the tiddler is changed\n // by code other than DataTiddler code. \n //\n // This is necessary since the data object is just a "cached version" \n // of the data defined in the data section of the tiddler and the \n // "external" change may have changed the content of the data section.\n // Thus we are not sure if the data object reflects the data section \n // contents. \n // \n // By deleting the data object we ensure that the data object is \n // reconstructed the next time it is needed, with the data defined by\n // the data section in the tiddler's text.\n \n // To indicate that a change is a "DataTiddler change" a temporary\n // property "isDataTiddlerChange" is added to the tiddler.\n if (this.dataObject && !this.isDataTiddlerChange) {\n delete this.dataObject;\n }\n \n // call the original code.\n DataTiddler.originalTiddlerChangedFunction.apply(this, arguments);\n}\n\n\n//============================================================================\n// Formatters\n//============================================================================\n\n// This formatter ensures that "~<data>" is rendered as "<data>". This is used to \n// escape the "<data>" of a data section, just in case someone really wants to use\n// "<data>" as a text in a tiddler and not start a data section.\n//\n// Same for </data>.\n//\nconfig.formatters.push( {\n name: "data-escape",\n match: "~<\s\s/?data>",\n\n handler: function(w) {\n w.outputText(w.output,w.matchStart + 1,w.nextMatch);\n }\n} )\n\n\n// This formatter ensures that <data>...</data> sections are not rendered.\n//\nconfig.formatters.push( {\n name: "data",\n match: "<data>",\n\n handler: function(w) {\n var info = DataTiddler.getDataSectionInfo(w.source);\n if (info && info.prefixEnd == w.matchStart) {\n w.nextMatch = info.suffixStart;\n } else {\n w.outputText(w.output,w.matchStart,w.nextMatch);\n }\n }\n} )\n\n\n//============================================================================\n// Tiddler Class Extension\n//============================================================================\n\n// "Hijack" the changed method ---------------------------------------------------\n\nDataTiddler.originalTiddlerChangedFunction = Tiddler.prototype.changed;\nTiddler.prototype.changed = DataTiddler.MyTiddlerChangedFunction;\n\n// Define accessor methods -------------------------------------------------------\n\n// Returns the value of the given data field of the tiddler. When no such field \n// is defined or its value is undefined the defaultValue is returned.\n//\n// When field is undefined (or null) the data object is returned. (See \n// DataTiddler.getDataObject.)\n//\n// @param field [may be null, undefined]\n// @param defaultValue [may be null, undefined]\n// @return [may be null, undefined]\n//\nTiddler.prototype.data = function(field, defaultValue) {\n return (field) \n ? DataTiddler.getTiddlerDataValue(this, field, defaultValue)\n : DataTiddler.getTiddlerDataObject(this);\n}\n\n// Sets the value of the given data field of the tiddler to the value. When the \n// value is equal to the defaultValue no value is set (and the field is removed).\n//\n// @param value [may be null, undefined]\n// @param defaultValue [may be null, undefined]\n//\nTiddler.prototype.setData = function(field, value, defaultValue) {\n DataTiddler.setTiddlerDataValue(this, field, value, defaultValue);\n}\n\n\n//============================================================================\n// showData Macro\n//============================================================================\n\nconfig.macros.showData = {\n // Standard Properties\n label: "showData",\n prompt: "Display the values stored in the data section of the tiddler"\n}\n\nconfig.macros.showData.handler = function(place,macroName,params) {\n // --- Parsing ------------------------------------------\n\n var i = 0; // index running over the params\n // Parse the optional "JSON"\n var showInJSONFormat = false;\n if ((i < params.length) && params[i] == "JSON") {\n i++;\n showInJSONFormat = true;\n }\n \n var tiddlerName = findContainingTiddler(place).id.substr(7);\n if (i < params.length) {\n tiddlerName = params[i]\n i++;\n }\n\n // --- Processing ------------------------------------------\n try {\n if (showInJSONFormat) {\n this.renderDataInJSONFormat(place, tiddlerName);\n } else {\n this.renderDataAsTable(place, tiddlerName);\n }\n } catch (e) {\n this.createErrorElement(place, e);\n }\n}\n\nconfig.macros.showData.renderDataInJSONFormat = function(place,tiddlerName) {\n var text = DataTiddler.getDataText(tiddlerName);\n if (text) {\n createTiddlyElement(place,"pre",null,null,text);\n }\n}\n\nconfig.macros.showData.renderDataAsTable = function(place,tiddlerName) {\n var text = "|!Name|!Value|\sn";\n var data = DataTiddler.getDataObject(tiddlerName);\n if (data) {\n for (var i in data) {\n var value = data[i];\n text += "|"+i+"|"+DataTiddler.stringify(value)+"|\sn";\n }\n }\n \n wikify(text, place);\n}\n\n\n// Internal.\n//\n// Creates an element that holds an error message\n// \nconfig.macros.showData.createErrorElement = function(place, exception) {\n var message = (exception.description) ? exception.description : exception.toString();\n return createTiddlyElement(place,"span",null,"showDataError","<<showData ...>>: "+message);\n}\n\n// ---------------------------------------------------------------------------\n// Stylesheet Extensions (may be overridden by local StyleSheet)\n// ---------------------------------------------------------------------------\n//\nsetStylesheet(\n ".showDataError{color: #ffffff;background-color: #880000;}",\n "showData");\n\n\n} // of "install only once"\n//}}}\n\n\n\n/***\n!JSON Code, used to serialize the data\n//(embedded in the plugin tiddler to make it selfcontained)//\n***/\n//{{{\n/*\nCopyright (c) 2005 JSON.org\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe Software shall be used for Good, not Evil.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n/*\n The global object JSON contains two methods.\n\n JSON.stringify(value) takes a JavaScript value and produces a JSON text.\n The value must not be cyclical.\n\n JSON.parse(text) takes a JSON text and produces a JavaScript value. It will\n throw a 'JSONError' exception if there is an error.\n*/\nvar JSON = {\n copyright: '(c)2005 JSON.org',\n license: 'http://www.crockford.com/JSON/license.html',\n/*\n Stringify a JavaScript value, producing a JSON text.\n*/\n stringify: function (v) {\n var a = [];\n\n/*\n Emit a string.\n*/\n function e(s) {\n a[a.length] = s;\n }\n\n/*\n Convert a value.\n*/\n function g(x) {\n var c, i, l, v;\n\n switch (typeof x) {\n case 'object':\n if (x) {\n if (x instanceof Array) {\n e('[');\n l = a.length;\n for (i = 0; i < x.length; i += 1) {\n v = x[i];\n if (typeof v != 'undefined' &&\n typeof v != 'function') {\n if (l < a.length) {\n e(',');\n }\n g(v);\n }\n }\n e(']');\n return;\n } else if (typeof x.toString != 'undefined') {\n e('{');\n l = a.length;\n for (i in x) {\n v = x[i];\n if (x.hasOwnProperty(i) &&\n typeof v != 'undefined' &&\n typeof v != 'function') {\n if (l < a.length) {\n e(',');\n }\n g(i);\n e(':');\n g(v);\n }\n }\n return e('}');\n }\n }\n e('null');\n return;\n case 'number':\n e(isFinite(x) ? +x : 'null');\n return;\n case 'string':\n l = x.length;\n e('"');\n for (i = 0; i < l; i += 1) {\n c = x.charAt(i);\n if (c >= ' ') {\n if (c == '\s\s' || c == '"') {\n e('\s\s');\n }\n e(c);\n } else {\n switch (c) {\n case '\sb':\n e('\s\sb');\n break;\n case '\sf':\n e('\s\sf');\n break;\n case '\sn':\n e('\s\sn');\n break;\n case '\sr':\n e('\s\sr');\n break;\n case '\st':\n e('\s\st');\n break;\n default:\n c = c.charCodeAt();\n e('\s\su00' + Math.floor(c / 16).toString(16) +\n (c % 16).toString(16));\n }\n }\n }\n e('"');\n return;\n case 'boolean':\n e(String(x));\n return;\n default:\n e('null');\n return;\n }\n }\n g(v);\n return a.join('');\n },\n/*\n Parse a JSON text, producing a JavaScript value.\n*/\n parse: function (text) {\n var p = /^\ss*(([,:{}\s[\s]])|"(\s\s.|[^\sx00-\sx1f"\s\s])*"|-?\sd+(\s.\sd*)?([eE][+-]?\sd+)?|true|false|null)\ss*/,\n token,\n operator;\n\n function error(m, t) {\n throw {\n name: 'JSONError',\n message: m,\n text: t || operator || token\n };\n }\n\n function next(b) {\n if (b && b != operator) {\n error("Expected '" + b + "'");\n }\n if (text) {\n var t = p.exec(text);\n if (t) {\n if (t[2]) {\n token = null;\n operator = t[2];\n } else {\n operator = null;\n try {\n token = eval(t[1]);\n } catch (e) {\n error("Bad token", t[1]);\n }\n }\n text = text.substring(t[0].length);\n } else {\n error("Unrecognized token", text);\n }\n } else {\n token = operator = undefined;\n }\n }\n\n\n function val() {\n var k, o;\n switch (operator) {\n case '{':\n next('{');\n o = {};\n if (operator != '}') {\n for (;;) {\n if (operator || typeof token != 'string') {\n error("Missing key");\n }\n k = token;\n next();\n next(':');\n o[k] = val();\n if (operator != ',') {\n break;\n }\n next(',');\n }\n }\n next('}');\n return o;\n case '[':\n next('[');\n o = [];\n if (operator != ']') {\n for (;;) {\n o.push(val());\n if (operator != ',') {\n break;\n }\n next(',');\n }\n }\n next(']');\n return o;\n default:\n if (operator !== null) {\n error("Missing value");\n }\n k = token;\n next();\n return k;\n }\n }\n next();\n return val();\n }\n};\n//}}}\n/***\n!Setup the data serialization\n***/\n//{{{\nDataTiddler.format = "JSON";\nDataTiddler.stringify = JSON.stringify;\nDataTiddler.parse = JSON.parse;\n\n//}}}\n\n
[[Introduction]]\nAboutStyles
/***\n|''Name:''|ForEachTiddlerPlugin|\n|''Version:''|1.0.4 (2006-01-06)|\n|''Source:''|http://tiddlywiki.abego-software.de/#ForEachTiddlerPlugin|\n|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|\n|''Licence:''|[[BSD open source license]]|\n|''Macros:''|[[ForEachTiddlerMacro]] v1.0.4|\n|''TiddlyWiki:''|1.2.38+, 2.0|\n|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|\n!Description\n\nCreate customizable lists, tables etc. for your selections of tiddlers. Specify the tiddlers to include and their order through a powerful language.\n\n''Syntax:'' \n|>|{{{<<}}}''forEachTiddler'' [''in'' //tiddlyWikiPath//] [''where'' //whereCondition//] [''sortBy'' //sortExpression// [''ascending'' //or// ''descending'']] [''script'' //scriptText//] [//action// [//actionParameters//]]{{{>>}}}|\n|//tiddlyWikiPath//|The filepath to the TiddlyWiki the macro should work on. When missing the current TiddlyWiki is used.|\n|//whereCondition//|(quoted) JavaScript boolean expression. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|\n|//sortExpression//|(quoted) JavaScript expression returning "comparable" objects (using '{{{<}}}','{{{>}}}','{{{==}}}'. May refer to the build-in variables {{{tiddler}}} and {{{context}}}.|\n|//scriptText//|(quoted) JavaScript text. Typically defines JavaScript functions that are called by the various JavaScript expressions (whereClause, sortClause, action arguments,...)|\n|//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.|\n|//actionParameters//|(action specific) parameters the action may refer while processing the tiddlers (see action descriptions for details). <<tiddler [[JavaScript in actionParameters]]>>|\n|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|\n\nSee details see [[ForEachTiddlerMacro]] and [[ForEachTiddlerExamples]].\n\n!Revision history\n* v1.0.4 (2006-01-06)\n** Support TiddlyWiki 2.0\n* v1.0.3 (2005-12-22)\n** Features: \n*** Write output to a file supports multi-byte environments (Thanks to Bram Chen) \n*** Provide API to access the forEachTiddler functionality directly through JavaScript (see getTiddlers and performMacro)\n** Enhancements:\n*** Improved error messages on InternetExplorer.\n* v1.0.2 (2005-12-10)\n** Features: \n*** context object also holds reference to store (TiddlyWiki)\n** Fixed Bugs: \n*** ForEachTiddler 1.0.1 has broken support on win32 Opera 8.51 (Thanks to BrunoSabin for reporting)\n* v1.0.1 (2005-12-08)\n** Features: \n*** Access tiddlers stored in separated TiddlyWikis through the "in" option. I.e. you are no longer limited to only work on the "current TiddlyWiki".\n*** Write output to an external file using the "toFile" option of the "write" action. With this option you may write your customized tiddler exports.\n*** Use the "script" section to define "helper" JavaScript functions etc. to be used in the various JavaScript expressions (whereClause, sortClause, action arguments,...).\n*** Access and store context information for the current forEachTiddler invocation (through the build-in "context" object) .\n*** Improved script evaluation (for where/sort clause and write scripts).\n* v1.0.0 (2005-11-20)\n** initial version\n\n!Code\n***/\n//{{{\n\n//============================================================================\n//============================================================================\n// ForEachTiddlerPlugin\n//============================================================================\n//============================================================================\n\nversion.extensions.ForEachTiddlerPlugin = {major: 1, minor: 0, revision: 4, date: new Date(2006,1,6), source: "http://tiddlywiki.abego-software.de/#ForEachTiddlergPlugin"};\n\n// For backward compatibility with TW 1.2.x\n//\nif (!TiddlyWiki.prototype.forEachTiddler) {\n TiddlyWiki.prototype.forEachTiddler = function(callback) {\n for(var t in this.tiddlers) {\n callback.call(this,t,this.tiddlers[t]);\n };\n }\n}\n\n//============================================================================\n// forEachTiddler Macro\n//============================================================================\n\nversion.extensions.forEachTiddler = {major: 1, minor: 0, revision: 4, date: new Date(2006,1,6), provider: "http://tiddlywiki.abego-software.de"};\n\n// ---------------------------------------------------------------------------\n// Configurations and constants \n// ---------------------------------------------------------------------------\n\nconfig.macros.forEachTiddler = {\n // Standard Properties\n label: "forEachTiddler",\n prompt: "Perform actions on a (sorted) selection of tiddlers",\n\n // actions\n actions: {\n addToList: {},\n write: {}\n }\n}\n\n// ---------------------------------------------------------------------------\n// The forEachTiddler Macro Handler \n// ---------------------------------------------------------------------------\n\nconfig.macros.forEachTiddler.handler = function(place,macroName,params) {\n // config.macros.forEachTiddler.traceMacroCall(place,macroName,params);\n\n // --- Parsing ------------------------------------------\n\n var i = 0; // index running over the params\n // Parse the "in" clause\n var tiddlyWikiPath = undefined;\n if ((i < params.length) && params[i] == "in") {\n i++;\n if (i >= params.length) {\n this.handleError(place, "TiddlyWiki path expected behind 'in'.");\n return;\n }\n tiddlyWikiPath = this.paramEncode((i < params.length) ? params[i] : "");\n i++;\n }\n\n // Parse the where clause\n var whereClause ="true";\n if ((i < params.length) && params[i] == "where") {\n i++;\n whereClause = this.paramEncode((i < params.length) ? params[i] : "");\n i++;\n }\n\n // Parse the sort stuff\n var sortClause = null;\n var sortAscending = true; \n if ((i < params.length) && params[i] == "sortBy") {\n i++;\n if (i >= params.length) {\n this.handleError(place, "sortClause missing behind 'sortBy'.");\n return;\n }\n sortClause = this.paramEncode(params[i]);\n i++;\n\n if ((i < params.length) && (params[i] == "ascending" || params[i] == "descending")) {\n sortAscending = params[i] == "ascending";\n i++;\n }\n }\n\n // Parse the script\n var scriptText = null;\n if ((i < params.length) && params[i] == "script") {\n i++;\n scriptText = this.paramEncode((i < params.length) ? params[i] : "");\n i++;\n }\n\n // Parse the action. \n // When we are already at the end use the default action\n var actionName = "addToList";\n if (i < params.length) {\n if (!config.macros.forEachTiddler.actions[params[i]]) {\n this.handleError(place, "Unknown action '"+params[i]+"'.");\n return;\n } else {\n actionName = params[i]; \n i++;\n }\n } \n \n // Get the action parameter\n // (the parsing is done inside the individual action implementation.)\n var actionParameter = params.slice(i);\n\n\n // --- Processing ------------------------------------------\n try {\n this.performMacro({\n place: place, \n whereClause: whereClause, \n sortClause: sortClause, \n sortAscending: sortAscending, \n actionName: actionName, \n actionParameter: actionParameter, \n scriptText: scriptText, \n tiddlyWikiPath: tiddlyWikiPath});\n\n } catch (e) {\n this.handleError(place, e);\n }\n}\n\n// Returns an object with properties "tiddlers" and "context".\n// tiddlers holds the (sorted) tiddlers selected by the parameter,\n// context the context of the execution of the macro.\n//\n// The action is not yet performed.\n//\n// @parameter see performMacro\n//\nconfig.macros.forEachTiddler.getTiddlersAndContext = function(parameter) {\n\n var context = config.macros.forEachTiddler.createContext(parameter.place, parameter.whereClause, parameter.sortClause, parameter.sortAscending, parameter.actionName, parameter.actionParameter, parameter.scriptText, parameter.tiddlyWikiPath);\n\n var tiddlyWiki = parameter.tiddlyWikiPath ? this.loadTiddlyWiki(parameter.tiddlyWikiPath) : store;\n context["tiddlyWiki"] = tiddlyWiki;\n \n // Get the tiddlers, as defined by the whereClause\n var tiddlers = this.findTiddlers(parameter.whereClause, context, tiddlyWiki);\n context["tiddlers"] = tiddlers;\n\n // Sort the tiddlers, when sorting is required.\n if (parameter.sortClause) {\n this.sortTiddlers(tiddlers, parameter.sortClause, parameter.sortAscending, context);\n }\n\n return {tiddlers: tiddlers, context: context};\n}\n\n// Returns the (sorted) tiddlers selected by the parameter.\n//\n// The action is not yet performed.\n//\n// @parameter see performMacro\n//\nconfig.macros.forEachTiddler.getTiddlers = function(parameter) {\n return this.getTiddlersAndContext(parameter).tiddlers;\n}\n\n// Performs the macros with the given parameter.\n//\n// @param parameter holds the parameter of the macro as separate properties.\n// The following properties are supported:\n//\n// place\n// whereClause\n// sortClause\n// sortAscending\n// actionName\n// actionParameter\n// scriptText\n// tiddlyWikiPath\n//\n// All properties are optional. \n// For most actions the place property must be defined.\n//\nconfig.macros.forEachTiddler.performMacro = function(parameter) {\n var tiddlersAndContext = this.getTiddlersAndContext(parameter);\n\n // Perform the action\n var actionName = parameter.actionName ? parameter.actionName : "addToList";\n var action = config.macros.forEachTiddler.actions[actionName];\n if (!action) {\n this.handleError(parameter.place, "Unknown action '"+actionName+"'.");\n return;\n }\n\n var actionHandler = action.handler;\n actionHandler(parameter.place, tiddlersAndContext.tiddlers, parameter.actionParameter, tiddlersAndContext.context);\n}\n\n// ---------------------------------------------------------------------------\n// The actions \n// ---------------------------------------------------------------------------\n\n// Internal.\n//\n// --- The addToList Action -----------------------------------------------\n//\nconfig.macros.forEachTiddler.actions.addToList.handler = function(place, tiddlers, parameter, context) {\n // Parse the parameter\n var p = 0;\n\n // Check for extra parameters\n if (parameter.length > p) {\n config.macros.forEachTiddler.createExtraParameterErrorElement(place, "addToList", parameter, p);\n return;\n }\n\n // Perform the action.\n var list = document.createElement("ul");\n place.appendChild(list);\n for (var i = 0; i < tiddlers.length; i++) {\n var tiddler = tiddlers[i];\n var listItem = document.createElement("li")\n list.appendChild(listItem);\n createTiddlyLink(listItem, tiddler.title, true);\n }\n}\n\n// Internal.\n//\n// --- The write Action ---------------------------------------------------\n//\nconfig.macros.forEachTiddler.actions.write.handler = function(place, tiddlers, parameter, context) {\n // Parse the parameter\n var p = 0;\n if (p >= parameter.length) {\n this.handleError(place, "Missing expression behind 'write'.");\n return;\n }\n\n var textExpression = config.macros.forEachTiddler.paramEncode(parameter[p]);\n p++;\n\n // Parse the "toFile" option\n var filename = null;\n var lineSeparator = undefined;\n if ((p < parameter.length) && parameter[p] == "toFile") {\n p++;\n if (p >= parameter.length) {\n this.handleError(place, "Filename expected behind 'toFile' of 'write' action.");\n return;\n }\n \n filename = config.macros.forEachTiddler.getLocalPath(config.macros.forEachTiddler.paramEncode(parameter[p]));\n p++;\n if ((p < parameter.length) && parameter[p] == "withLineSeparator") {\n p++;\n if (p >= parameter.length) {\n this.handleError(place, "Line separator text expected behind 'withLineSeparator' of 'write' action.");\n return;\n }\n lineSeparator = config.macros.forEachTiddler.paramEncode(parameter[p]);\n p++;\n }\n }\n \n // Check for extra parameters\n if (parameter.length > p) {\n config.macros.forEachTiddler.createExtraParameterErrorElement(place, "write", parameter, p);\n return;\n }\n\n // Perform the action.\n var func = config.macros.forEachTiddler.getEvalTiddlerFunction(textExpression, context);\n var count = tiddlers.length;\n var text = "";\n for (var i = 0; i < count; i++) {\n var tiddler = tiddlers[i];\n text += func(tiddler, context, count, i);\n }\n \n if (filename) {\n if (lineSeparator != undefined) {\n lineSeparator = lineSeparator.replace(/\s\sn/mg, "\sn").replace(/\s\sr/mg, "\sr");\n text = text.replace(/\sn/mg,lineSeparator);\n }\n saveFile(filename, convertUnicodeToUTF8(text));\n } else {\n var wrapper = createTiddlyElement(place, "span");\n wikify(text, wrapper);\n }\n}\n\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n// Internal.\n//\nconfig.macros.forEachTiddler.createContext = function(placeParam, whereClauseParam, sortClauseParam, sortAscendingParam, actionNameParam, actionParameterParam, scriptText, tiddlyWikiPathParam) {\n return {\n place : placeParam, \n whereClause : whereClauseParam, \n sortClause : sortClauseParam, \n sortAscending : sortAscendingParam, \n script : scriptText,\n actionName : actionNameParam, \n actionParameter : actionParameterParam,\n tiddlyWikiPath : tiddlyWikiPathParam\n }\n}\n\n// Internal.\n//\n// Returns a TiddlyWiki with the tiddlers loaded from the TiddlyWiki of \n// the given path.\n//\nconfig.macros.forEachTiddler.loadTiddlyWiki = function(path, idPrefix) {\n if (!idPrefix) {\n idPrefix = "store";\n }\n \n // Read the content of the given file\n var content = loadFile(this.getLocalPath(path));\n if(content == null) {\n throw "TiddlyWiki '"+path+"' not found.";\n }\n \n // Locate the storeArea div's\n var posOpeningDiv = content.indexOf(startSaveArea);\n var posClosingDiv = content.lastIndexOf(endSaveArea);\n if((posOpeningDiv == -1) || (posClosingDiv == -1)) {\n throw "File '"+path+"' is not a TiddlyWiki.";\n }\n var storageText = content.substr(posOpeningDiv + startSaveArea.length, posClosingDiv);\n \n // Create a "div" element that contains the storage text\n var myStorageDiv = document.createElement("div");\n myStorageDiv.innerHTML = storageText;\n myStorageDiv.normalize();\n \n // Create all tiddlers in a new TiddlyWiki\n // (following code is modified copy of TiddlyWiki.prototype.loadFromDiv)\n var tiddlyWiki = new TiddlyWiki();\n var store = myStorageDiv.childNodes;\n for(var t = 0; t < store.length; t++) {\n var e = store[t];\n var title = null;\n if(e.getAttribute)\n title = e.getAttribute("tiddler");\n if(!title && e.id && e.id.substr(0,lenPrefix) == idPrefix)\n title = e.id.substr(lenPrefix);\n if(title && title != "") {\n var tiddler = tiddlyWiki.createTiddler(title);\n tiddler.loadFromDiv(e,title);\n }\n }\n tiddlyWiki.dirty = false;\n\n return tiddlyWiki;\n}\n\n\n \n// Internal.\n//\n// Returns a function that has a function body returning the given javaScriptExpression.\n// The function has the parameters:\n// \n// (tiddler, context, count, index)\n//\nconfig.macros.forEachTiddler.getEvalTiddlerFunction = function (javaScriptExpression, context) {\n var script = context["script"];\n var functionText = "theFunction = function(tiddler, context, count, index) { return "+javaScriptExpression+"}";\n var fullText = (script ? script+";" : "")+functionText;\n return eval(fullText);\n}\n\n// Internal.\n//\nconfig.macros.forEachTiddler.findTiddlers = function(whereClause, context, tiddlyWiki) {\n var result = [];\n var func = config.macros.forEachTiddler.getEvalTiddlerFunction(whereClause, context);\n tiddlyWiki.forEachTiddler(function(title,tiddler) {\n if (func(tiddler, context, undefined, undefined)) {\n result.push(tiddler);\n }\n });\n return result;\n}\n\n// Internal.\n//\nconfig.macros.forEachTiddler.createExtraParameterErrorElement = function(place, actionName, parameter, firstUnusedIndex) {\n var message = "Extra parameter behind '"+actionName+"':";\n for (var i = firstUnusedIndex; i < parameter.length; i++) {\n message += " "+parameter[i];\n }\n this.handleError(place, message);\n}\n\n// Internal.\n//\nconfig.macros.forEachTiddler.sortAscending = function(tiddlerA, tiddlerB) {\n var result = \n (tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) \n ? 0\n : (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)\n ? -1 \n : +1; \n return result;\n}\n\n// Internal.\n//\nconfig.macros.forEachTiddler.sortDescending = function(tiddlerA, tiddlerB) {\n var result = \n (tiddlerA.forEachTiddlerSortValue == tiddlerB.forEachTiddlerSortValue) \n ? 0\n : (tiddlerA.forEachTiddlerSortValue < tiddlerB.forEachTiddlerSortValue)\n ? +1 \n : -1; \n return result;\n}\n\n// Internal.\n//\nconfig.macros.forEachTiddler.sortTiddlers = function(tiddlers, sortClause, ascending, context) {\n // To avoid evaluating the sortClause whenever two items are compared \n // we pre-calculate the sortValue for every item in the array and store it in a \n // temporary property ("forEachTiddlerSortValue") of the tiddlers.\n var func = config.macros.forEachTiddler.getEvalTiddlerFunction(sortClause, context);\n var count = tiddlers.length;\n for (var i = 0; i < count; i++) {\n var tiddler = tiddlers[i];\n tiddler.forEachTiddlerSortValue = func(tiddler,context, undefined, undefined);\n }\n\n // Do the sorting\n tiddlers.sort(ascending ? this.sortAscending : this.sortDescending);\n\n // Delete the temporary property that holds the sortValue. \n for (var i = 0; i < tiddlers.length; i++) {\n delete tiddlers[i].forEachTiddlerSortValue;\n }\n}\n\n\n// Internal.\n//\nconfig.macros.forEachTiddler.trace = function(message) {\n displayMessage(message);\n}\n\n// Internal.\n//\nconfig.macros.forEachTiddler.traceMacroCall = function(place,macroName,params) {\n var message ="<<"+macroName;\n for (var i = 0; i < params.length; i++) {\n message += " "+params[i];\n }\n message += ">>";\n displayMessage(message);\n}\n\n\n// Internal.\n//\n// Creates an element that holds an error message\n// \nconfig.macros.forEachTiddler.createErrorElement = function(place, exception) {\n var message = (exception.description) ? exception.description : exception.toString();\n return createTiddlyElement(place,"span",null,"forEachTiddlerError","<<forEachTiddler ...>>: "+message);\n}\n\n// Internal.\n//\n// @param place [may be null]\n//\nconfig.macros.forEachTiddler.handleError = function(place, exception) {\n if (place) {\n this.createErrorElement(place, exception);\n } else {\n throw exception;\n }\n}\n\n// Internal.\n//\n// Encodes the given string.\n//\n// Replaces \n// "$))" to ">>"\n// "$)" to ">"\n//\nconfig.macros.forEachTiddler.paramEncode = function(s) {\n var reGTGT = new RegExp("\s\s$\s\s)\s\s)","mg");\n var reGT = new RegExp("\s\s$\s\s)","mg");\n return s.replace(reGTGT, ">>").replace(reGT, ">");\n}\n\n// Internal.\n//\n// Returns the given original path (that is a file path, starting with "file:")\n// as a path to a local file, in the systems native file format.\n//\n// Location information in the originalPath (i.e. the "#" and stuff following)\n// is stripped.\n// \nconfig.macros.forEachTiddler.getLocalPath = function(originalPath) {\n // Remove any location part of the URL\n var hashPos = originalPath.indexOf("#");\n if(hashPos != -1)\n originalPath = originalPath.substr(0,hashPos);\n // Convert to a native file format assuming\n // "file:///x:/path/path/path..." - pc local file --> "x:\spath\spath\spath..."\n // "file://///server/share/path/path/path..." - FireFox pc network file --> "\s\sserver\sshare\spath\spath\spath..."\n // "file:///path/path/path..." - mac/unix local file --> "/path/path/path..."\n // "file://server/share/path/path/path..." - pc network file --> "\s\sserver\sshare\spath\spath\spath..."\n var localPath;\n if(originalPath.charAt(9) == ":") // pc local file\n localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file:///") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(7));\n else if(originalPath.indexOf("file:/") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(5));\n else // pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\s\s"); \n return localPath;\n}\n\n// ---------------------------------------------------------------------------\n// Stylesheet Extensions (may be overridden by local StyleSheet)\n// ---------------------------------------------------------------------------\n//\nsetStylesheet(\n ".forEachTiddlerError{color: #ffffff;background-color: #880000;}",\n "forEachTiddler");\n\n//============================================================================\n// End of forEachTiddler Macro\n//============================================================================\n\n\n//============================================================================\n// String.startsWith Function\n//============================================================================\n//\n// Returns true if the string starts with the given prefix, false otherwise.\n//\nversion.extensions["String.startsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nString.prototype.startsWith = function(prefix) {\n var n = prefix.length;\n return (this.length >= n) && (this.slice(0, n) == prefix);\n}\n\n\n\n//============================================================================\n// String.endsWith Function\n//============================================================================\n//\n// Returns true if the string ends with the given suffix, false otherwise.\n//\nversion.extensions["String.endsWith"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nString.prototype.endsWith = function(suffix) {\n var n = suffix.length;\n return (this.length >= n) && (this.right(n) == suffix);\n}\n\n\n//============================================================================\n// String.contains Function\n//============================================================================\n//\n// Returns true when the string contains the given substring, false otherwise.\n//\nversion.extensions["String.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nString.prototype.contains = function(substring) {\n return this.indexOf(substring) >= 0;\n}\n\n//============================================================================\n// Array.indexOf Function\n//============================================================================\n//\n// Returns the index of the first occurance of the given item in the array or \n// -1 when no such item exists.\n//\n// @param item [may be null]\n//\nversion.extensions["Array.indexOf"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nArray.prototype.indexOf = function(item) {\n for (var i = 0; i < this.length; i++) {\n if (this[i] == item) {\n return i;\n }\n }\n return -1;\n}\n\n//============================================================================\n// Array.contains Function\n//============================================================================\n//\n// Returns true when the array contains the given item, otherwise false. \n//\n// @param item [may be null]\n//\nversion.extensions["Array.contains"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nArray.prototype.contains = function(item) {\n return (this.indexOf(item) >= 0);\n}\n\n//============================================================================\n// Array.containsAny Function\n//============================================================================\n//\n// Returns true when the array contains at least one of the elements \n// of the item. Otherwise (or when items contains no elements) false is returned.\n//\nversion.extensions["Array.containsAny"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nArray.prototype.containsAny = function(items) {\n for(var i = 0; i < items.length; i++) {\n if (this.contains(items[i])) {\n return true;\n }\n }\n return false;\n}\n\n\n//============================================================================\n// Array.containsAll Function\n//============================================================================\n//\n// Returns true when the array contains all the items, otherwise false.\n// \n// When items is null false is returned (even if the array contains a null).\n//\n// @param items [may be null] \n//\nversion.extensions["Array.containsAll"] = {major: 1, minor: 0, revision: 0, date: new Date(2005,11,20), provider: "http://tiddlywiki.abego-software.de"};\n//\nArray.prototype.containsAll = function(items) {\n for(var i = 0; i < items.length; i++) {\n if (!this.contains(items[i])) {\n return false;\n }\n }\n return true;\n}\n\n\n\n//}}}\n\n\n/***\n!Licence and Copyright\nCopyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or other\nmaterials provided with the distribution.\n\nNeither the name of abego Software nor the names of its contributors may be\nused to endorse or promote products derived from this software without specific\nprior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\nSHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.\n***/\n
/***\n<<checkForDataTiddlerPlugin>>\n|''Name:''|FormTiddlerPlugin|\n|''Version:''|1.0.2 (2006-01-06)|\n|''Source:''|http://tiddlywiki.abego-software.de/#FormTiddlerPlugin|\n|''Author:''|UdoBorkowski (ub [at] abego-software [dot] de)|\n|''Licence:''|[[BSD open source license]]|\n|''Macros:''|formTiddler 1.0.2, checkForDataTiddlerPlugin 1.0.0, newTiddlerWithForm 1.0.1|\n|''Requires:''|DataTiddlerPlugin|\n|''TiddlyWiki:''|1.2.38+, 2.0|\n|''Browser:''|Firefox 1.0.4+; InternetExplorer 6.0|\n!Description\nUse form-based tiddlers to enter your tiddler data using text fields, listboxes, checkboxes etc. (All standard HTML Form input elements supported).\n\n''Syntax:'' \n|>|{{{<<}}}''formTiddler'' //tiddlerName//{{{>>}}}|\n|//tiddlerName//|The name of the FormTemplate tiddler to be used to edit the data of the tiddler containing the macro.|\n\n|>|{{{<<}}}''newTiddlerWithForm'' //formTemplateName// //buttonLabel// [//titleExpression// [''askUser'']] {{{>>}}}|\n|//formTemplateName//|The name of the tiddler that defines the form the new tiddler should use.|\n|//buttonLabel//|The label of the button|\n|//titleExpression//|A (quoted) JavaScript String expression that defines the title (/name) of the new tiddler.|\n|''askUser''|Typically the user is not asked for the title when a title is specified (and not yet used). When ''askUser'' is given the user will be asked in any case. This may be used when the calculated title is just a suggestion that must be confirmed by the user|\n|>|~~Syntax formatting: Keywords in ''bold'', optional parts in [...]. 'or' means that exactly one of the two alternatives must exist.~~|\n\nFor details and how to use the macros see the [[introduction|FormTiddler Introduction]] and the [[examples|FormTiddler Examples]].\n\n!Revision history\n* v1.0.2 (2006-01-06)\n** Support TiddlyWiki 2.0\n* v1.0.1 (2005-12-22)\n** Features: \n*** Support InternetExplorer\n*** Added newTiddlerWithForm Macro\n* v1.0.0 (2005-12-14)\n** initial version\n\n!Code\n***/\n//{{{\n\n//============================================================================\n//============================================================================\n// FormTiddlerPlugin\n//============================================================================\n//============================================================================\n\n\nversion.extensions.FormTiddlerPlugin = {\n major: 1, minor: 0, revision: 2,\n date: new Date(2006, 1, 6), \n type: 'plugin',\n source: "http://tiddlywiki.abego-software.de/#FormTiddlerPlugin"\n};\n\n// For backward compatibility with v1.2.x\n//\nif (!window.story) window.story=window; \nif (!TiddlyWiki.prototype.getTiddler) TiddlyWiki.prototype.getTiddler = function(title) { return t = this.tiddlers[title]; return (t != undefined && t instanceof Tiddler) ? t : null; } \n\n//============================================================================\n// formTiddler Macro\n//============================================================================\n\n// -------------------------------------------------------------------------------\n// Configurations and constants \n// -------------------------------------------------------------------------------\n\nconfig.macros.formTiddler = {\n // Standard Properties\n label: "formTiddler",\n version: {major: 1, minor: 0, revision: 2, date: new Date(2006, 1, 6)},\n prompt: "Edit tiddler data using forms",\n\n // Define the "setters" that set the values of INPUT elements of a given type\n // (must match the corresponding "getter")\n setter: { \n button: function(e, value) {/*contains no data */ },\n checkbox: function(e, value) {e.checked = value;},\n file: function(e, value) {try {e.value = value;} catch(e) {/* ignore, possibly security error*/}},\n hidden: function(e, value) {e.value = value;},\n password: function(e, value) {e.value = value;},\n radio: function(e, value) {e.checked = (e.value == value);},\n reset: function(e, value) {/*contains no data */ },\n "select-one": function(e, value) {config.macros.formTiddler.setSelectOneValue(e,value);},\n "select-multiple": function(e, value) {config.macros.formTiddler.setSelectMultipleValue(e,value);},\n submit: function(e, value) {/*contains no data */},\n text: function(e, value) {e.value = value;},\n textarea: function(e, value) {e.value = value;}\n },\n\n // Define the "getters" that return the value of INPUT elements of a given type\n // Return undefined to not store any data.\n getter: { \n button: function(e, value) {return undefined;},\n checkbox: function(e, value) {return e.checked;},\n file: function(e, value) {return e.value;},\n hidden: function(e, value) {return e.value;},\n password: function(e, value) {return e.value;},\n radio: function(e, value) {return e.checked ? e.value : undefined;},\n reset: function(e, value) {return undefined;},\n "select-one": function(e, value) {return config.macros.formTiddler.getSelectOneValue(e);},\n "select-multiple": function(e, value) {return config.macros.formTiddler.getSelectMultipleValue(e);},\n submit: function(e, value) {return undefined;},\n text: function(e, value) {return e.value;},\n textarea: function(e, value) {return e.value;}\n }\n};\n\n\n// -------------------------------------------------------------------------------\n// The formTiddler Macro Handler \n// -------------------------------------------------------------------------------\n\nconfig.macros.formTiddler.handler = function(place,macroName,params,wikifier,params,tiddler) {\n if (!config.macros.formTiddler.checkForExtensions(place, macroName)) {\n return;\n }\n \n // --- Parsing ------------------------------------------\n\n var i = 0; // index running over the params\n\n // get the name of the form template tiddler\n var formTemplateName = undefined;\n if (i < params.length) {\n formTemplateName = params[i];\n i++;\n }\n\n if (!formTemplateName) {\n config.macros.formTiddler.createErrorElement(place, "No form template specified in <<" + macroName + ">>.");\n return;\n }\n\n\n // --- Processing ------------------------------------------\n\n // Get the form template text. \n // (This contains the INPUT elements for the form.)\n var formTemplateTiddler = store.getTiddler(formTemplateName);\n if (!formTemplateTiddler) {\n config.macros.formTiddler.createErrorElement(place, "Form template '" + formTemplateName + "' not found.");\n return;\n }\n var templateText = formTemplateTiddler.text;\n if(!templateText) {\n // Shortcut: when template text is empty we do nothing.\n return;\n }\n\n // Get the name of the tiddler containing this "formTiddler" macro\n // (i.e. the tiddler, that will be edited and that contains the data)\n var tiddlerName = config.macros.formTiddler.getContainingTiddlerName(place);\n\n // Append a "form" element. \n var formName = "form"+formTemplateName+"__"+tiddlerName;\n var e = document.createElement("form");\n e.setAttribute("name", formName);\n place.appendChild(e);\n\n // "Embed" the elements defined by the templateText (i.e. the INPUT elements) \n // into the "form" element we just created\n wikify(templateText, e);\n\n // Initialize the INPUT elements.\n config.macros.formTiddler.initValuesAndHandlersInFormElements(formName, DataTiddler.getDataObject(tiddlerName));\n}\n\n\n// -------------------------------------------------------------------------------\n// Form Data Access \n// -------------------------------------------------------------------------------\n\n// Internal.\n//\n// Initialize the INPUT elements of the form with the values of their "matching"\n// data fields in the tiddler. Also setup the onChange handler to ensure that\n// changes in the INPUT elements are stored in the tiddler's data.\n//\nconfig.macros.formTiddler.initValuesAndHandlersInFormElements = function(formName, data) {\n // config.macros.formTiddler.trace("initValuesAndHandlersInFormElements(formName="+formName+", data="+data+")");\n\n // find the form\n var form = config.macros.formTiddler.findForm(formName);\n if (!form) {\n return;\n }\n\n try {\n var elems = form.elements;\n for (var i = 0; i < elems.length; i++) {\n var c = elems[i];\n \n var setter = config.macros.formTiddler.setter[c.type];\n if (setter) {\n var value = data[c.name];\n if (value != null) {\n setter(c, value);\n }\n c.setAttribute("onchange", "window.onFormTiddlerChange(event)");\n } else {\n config.macros.formTiddler.displayFormTiddlerError("No setter defined for INPUT element of type '"+c.type+"'. (Element '"+c.name+"' in form '"+formName+"')");\n }\n }\n } catch(e) {\n config.macros.formTiddler.displayFormTiddlerError("Error when updating elements with new formData. "+e);\n }\n}\n\n\n// Internal.\n//\n// @return [may be null]\n//\nconfig.macros.formTiddler.findForm = function(formName) {\n // We must manually iterate through the document's forms, since\n // IE does not support the "document[formName]" approach\n\n var forms = window.document.forms;\n for (var i = 0; i < forms.length; i++) {\n var form = forms[i];\n if (form.name == formName) {\n return form;\n }\n }\n\n return null;\n}\n\n\n// Internal.\n//\nconfig.macros.formTiddler.setSelectOneValue = function(element,value) {\n var n = element.options.length;\n for (var i = 0; i < n; i++) {\n element.options[i].selected = element.options[i].value == value;\n }\n}\n\n// Internal.\n//\nconfig.macros.formTiddler.setSelectMultipleValue = function(element,value) {\n var values = {};\n for (var i = 0; i < value.length; i++) {\n values[value[i]] = true;\n }\n \n var n = element.length;\n for (var i = 0; i < n; i++) {\n element.options[i].selected = !(!values[element.options[i].value]);\n }\n}\n\n// Internal.\n//\nconfig.macros.formTiddler.getSelectOneValue = function(element) {\n var i = element.selectedIndex;\n return (i >= 0) ? element.options[i].value : null;\n}\n\n// Internal.\n//\nconfig.macros.formTiddler.getSelectMultipleValue = function(element) {\n var values = [];\n var n = element.length;\n for (var i = 0; i < n; i++) {\n if (element.options[i].selected) {\n values.push(element.options[i].value);\n }\n }\n return values;\n}\n\n\n\n// -------------------------------------------------------------------------------\n// Helpers \n// -------------------------------------------------------------------------------\n\n// Internal.\n//\nconfig.macros.formTiddler.checkForExtensions = function(place,macroName) {\n if (!version.extensions.DataTiddlerPlugin) {\n config.macros.formTiddler.createErrorElement(place, "<<" + macroName + ">> requires the DataTiddlerPlugin. (You can get it from http://tiddlywiki.abego-software.de/#DataTiddlerPlugin)");\n return false;\n }\n return true;\n}\n\n// Internal.\n//\n// Displays a trace message in the "TiddlyWiki" message pane.\n// (used for debugging)\n//\nconfig.macros.formTiddler.trace = function(s) {\n displayMessage("Trace: "+s);\n}\n\n// Internal.\n//\n// Display some error message in the "TiddlyWiki" message pane.\n//\nconfig.macros.formTiddler.displayFormTiddlerError = function(s) {\n debugger;\n alert("FormTiddlerPlugin Error: "+s);\n}\n\n// Internal.\n//\n// Creates an element that holds an error message\n// \nconfig.macros.formTiddler.createErrorElement = function(place, message) {\n return createTiddlyElement(place,"span",null,"formTiddlerError",message);\n}\n\n// Internal.\n//\n// Returns the name of the tiddler containing the given element.\n// \nconfig.macros.formTiddler.getContainingTiddlerName = function(element) {\n return story.findContainingTiddler(element).id.substr(7);\n}\n\n// -------------------------------------------------------------------------------\n// Event Handlers \n// -------------------------------------------------------------------------------\n\n// This function must be called by the INPUT elements whenever their\n// data changes. Typically this is done through an "onChange" handler.\n//\nfunction onFormTiddlerChange (e) {\n // config.macros.formTiddler.trace("onFormTiddlerChange "+e);\n\n if (!e) var e = window.event;\n\n var target = resolveTarget(e);\n var tiddlerName = config.macros.formTiddler.getContainingTiddlerName(target);\n var getter = config.macros.formTiddler.getter[target.type];\n if (getter) {\n var value = getter(target);\n DataTiddler.setData(tiddlerName, target.name, value);\n } else {\n config.macros.formTiddler.displayFormTiddlerError("No getter defined for INPUT element of type '"+target.type+"'. (Element '"+target.name+"' used in tiddler '"+tiddlerName+"')");\n }\n}\n\n// ensure that the function can be used in HTML event handler\nwindow.onFormTiddlerChange = onFormTiddlerChange;\n\n\n// -------------------------------------------------------------------------------\n// Stylesheet Extensions (may be overridden by local StyleSheet)\n// -------------------------------------------------------------------------------\n\nsetStylesheet(\n ".formTiddlerError{color: #ffffff;background-color: #880000;}",\n "formTiddler");\n\n\n//============================================================================\n// checkForDataTiddlerPlugin Macro\n//============================================================================\n\nconfig.macros.checkForDataTiddlerPlugin = {\n // Standard Properties\n label: "checkForDataTiddlerPlugin",\n version: {major: 1, minor: 0, revision: 0, date: new Date(2005, 12, 14)},\n prompt: "Check if the DataTiddlerPlugin exists"\n}\n\nconfig.macros.checkForDataTiddlerPlugin.handler = function(place,macroName,params) {\n config.macros.formTiddler.checkForExtensions(place, config.macros.formTiddler.label);\n}\n\n\n\n//============================================================================\n// newTiddlerWithForm Macro\n//============================================================================\n\nconfig.macros.newTiddlerWithForm = {\n // Standard Properties\n label: "newTiddlerWithForm",\n version: {major: 1, minor: 0, revision: 1, date: new Date(2006, 1, 6)},\n prompt: "Creates a new Tiddler with a <<formTiddler ...>> macro"\n}\n\nconfig.macros.newTiddlerWithForm.handler = function(place,macroName,params) {\n // --- Parsing ------------------------------------------\n\n var i = 0; // index running over the params\n\n // get the name of the form template tiddler\n var formTemplateName = undefined;\n if (i < params.length) {\n formTemplateName = params[i];\n i++;\n }\n\n if (!formTemplateName) {\n config.macros.formTiddler.createErrorElement(place, "No form template specified in <<" + macroName + ">>.");\n return;\n }\n\n // get the button label\n var buttonLabel = undefined;\n if (i < params.length) {\n buttonLabel = params[i];\n i++;\n }\n\n if (!buttonLabel) {\n config.macros.formTiddler.createErrorElement(place, "No button label specified in <<" + macroName + ">>.");\n return;\n }\n\n // get the (optional) tiddlerName script and "askUser"\n var tiddlerNameScript = undefined;\n var askUser = false;\n if (i < params.length) {\n tiddlerNameScript = params[i];\n i++;\n\n if (i < params.length && params[i] == "askUser") {\n askUser = true;\n i++;\n }\n }\n\n // --- Processing ------------------------------------------\n\n if(!readOnly) {\n var onClick = function() {\n var tiddlerName;\n if (tiddlerNameScript) {\n try {\n tiddlerName = eval(tiddlerNameScript);\n } catch (ex) {\n }\n }\n if (!tiddlerName || askUser) {\n tiddlerName = prompt("Please specify a tiddler name.", askUser ? tiddlerName : "");\n }\n while (tiddlerName && store.getTiddler(tiddlerName)) {\n tiddlerName = prompt("A tiddler named '"+tiddlerName+"' already exists.\sn\sn"+"Please specify a tiddler name.", tiddlerName);\n }\n\n // tiddlerName is either null (user canceled) or a name that is not yet in the store.\n if (tiddlerName) {\n var body = "<<formTiddler [["+formTemplateName+"]]>>";\n var tags = [];\n store.saveTiddler(tiddlerName,tiddlerName,body,config.options.txtUserName,new Date(),tags);\n story.displayTiddler(null,tiddlerName,1);\n }\n }\n\n createTiddlyButton(place,buttonLabel,buttonLabel,onClick);\n }\n}\n\n//}}}\n\n\n/***\n!Licence and Copyright\nCopyright (c) abego Software ~GmbH, 2005 ([[www.abego-software.de|http://www.abego-software.de]])\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or other\nmaterials provided with the distribution.\n\nNeither the name of abego Software nor the names of its contributors may be\nused to endorse or promote products derived from this software without specific\nprior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY\nEXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\nSHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\nTO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\nBUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN\nANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.\n***/\n
!New Tasks\nClick task to edit it and assign tags.\n\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.tags.contains("in")' \n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>\n\n!Inbox tiddlers\nNon-task tiddlers with the tag {{{in}}}. (This list does not automatically refresh.)\n\n<<forEachTiddler\n where\n '!tiddler.tags.contains("tt_task") && tiddler.tags.contains("in")' \n sortBy\n 'tiddler.created'\n write\n '"*[["+tiddler.title+"]] ("+tiddler.tags.join("; ")+")\sn"'\n>>\n\n!All Untagged\n(This list does not automatically refresh.)\n<<forEachTiddler\n where\n '!tiddler.tags || (tiddler.tags.length==0)'\n sortBy\n 'tiddler.created'\n write\n '"*[["+tiddler.title+"]]\sn"'\n>>
This is the second beta release of [[TiddlyTracks|TiddlyTracksPlugin]] and the [[Clean Green Style Sheet|StyleSheet]].\nNothing works in Internet Explorer at the moment.\n\n!The Basics So Far\n*There is an ''add new task'' text box on the sidebar.\n* Type something there and press "Enter". Your text will show up on the MasterTaskList (and Inbox above).\n* Or type something like "blahProject netSurf'';;;''research widgets" and the new task will have the tags "blahProject" and "netSurf" (but it will not show in Inbox unless you also tag it "in").\n* Edit task by clicking on it in MasterTaskList\n* Copy the master task list forEachTiddler to make your our tag-based task lists. Be sure to tag the tiddler with "tt_taskList"\n* You could also tag an existing tiddler with "tt_task" and the text of that tiddler will show up as a task.\n\n!Biggest Problems\n* Need to fix plugin for ''IE'' use\n* Relies on refreshing all task lists in story area to update task references. So if you're editing a task list tiddler and make a change to a task or task list then your editing is lost (I'll fix this later).\n** I would prefer to use tiddler references to update but there are some tricky issues.\n\n!New\n* Open task for editing by clicking on it in task list. Changes to standard tiddler stuff must be saved but task changes are saved automatically (must press save or close to update task list).\n* Delete task "button" on task list. (Udo's forEach macro design is even cooler than I thought.)\n* TiddlyTracksSideBar is a separate, optional tiddler. If user wants to use it, they must include it in SideBarOptions.\n* Horizontal main menu StyleSheet.\n\n!Coming Soon\n*More commands for the add new task box like append to existing tiddler\n*Discussion of/integration with other task and reminder systems\n*Waiting for other people's plugins for:\n**Better task tag management\n**Pull-down menu for locale contexts (GTD @Phone, etc). See MoreExamples.\n\n![[TiddlyTracks|TiddlyTracksPlugin]]:\n* is much inspired by the clean style of rousette.org.uk's [[Tracks|http://www.rousette.org.uk/projects/]] ~GTD-inspired organizing thingie [[(screenshot)|http://www.rousette.org.uk/projects/images/15.png]] \n* uses [[Udo's Plugins|http://tiddlywiki.abego-software.de/]] and much of MPTW's styles\n* requires TiddlyWiki 2.0. I made messier, more basic version pre -2.0 but eh.\n
var attr = "";\n for (var i = 0; i<containingTiddler.attributes.length; i++) {\n attr+=containingTiddler.attributes[i].name+"->"+containingTiddler.attributes[i].value+"\sn"; \n }\n
/***\n<html>\n<input type='text' width='15' onkeyup='keyUpTest(event)' />\n</html>\n***/\n\n//{{{\nfunction keyUpTest(e) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n // TODO error check proper input\n alert("Key: "+e.keyCode +" Value: "+target.value);\n return false;\n}\n//}}}\n
*[[Home|Introduction]]\n*TiddlyTracksPlugin\n*[[Inbox]]\n*[[Next|NextActions]]\n*[[All|MasterTaskList]]\n*[[More Examples]]\n*MyMenu\n*[[*|AllShadowedTiddlers]]
<html>\n<input name="statusIsDone" type="checkbox" /> \n<textarea name="taskText" rows="2" cols="40"></textarea>\n</html><data>{"titlePrefix":"tt_task_","defaultTags":["tt_task","excludeLists"]}</data>
Click task item below to edit it.\n\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task")'\n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>\n
''Don't forget to tag task lists as "tt_taskList"!''\n\n!Tasks for a specific project\nTasks tagged {{{tt}}} are for the TiddlyTracks project.\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.tags.contains("tt") '\n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>\n\n!To Call\nTag a task as {{{call}}} and it will show up here.\n\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.tags.contains("call") '\n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>\n\n!To E-mail\nTag a task as {{{ttem}}} and it will show up here.\n\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.tags.contains("ttem") '\n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>\n\n!All Completed Tasks\nIf the checkbox is checked, it will show up here.\n\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.data("statusIsDone") '\n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>
(Turn this into a pulldown when someone posts how.)\n!Edit MainMenu\n\n!Secret Tiddlers\nSideBarOptions\nPageTemplate\nAllShadowedTiddlers\n\nOldCurrentAction\n[[Introduction]]\n\n
Tag a task as {{{next}}} and it will show up here.\n\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.tags.contains("next") '\n sortBy\n 'tiddler.created'\n writeTtTaskLine\n 'MasterTaskList'\n>>\n
!Task List View\n\n* if delete when completed, then DO NOT show deleteTask\n\n* task list has options\n** delete when completed (checked)\n\n* refresh list on delete tiddler\n** Note: If tiddler TabTimeline is open. It does not update if a new tiddler is added or deleted!\n** make Tag-Based Refresh?\n*** see TagBasedTemplatesPlugin\n*** overwrite refreshDisplay to refreshTiddler on all with tag blah1, blah2, blah3\n\n* edit tags\n\n! Tabs/horizontal menu\n* http://simonbaird.com/mptw/
<!---\nBased on MPTW horizontal main menu (http://simonbaird.com/mptw/)\n--->\n<!--{{{-->\n<div class='header'>\n <div class='headerForeground'>\n <span class='siteTitle' refresh='content' tiddler='SiteTitle'></span><br/>\n <span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>\n </div>\n <div id='topMenu' refresh='content' tiddler='MainMenu'></div>\n</div>\n<div id='sidebar'>\n <div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>\n <div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>\n</div>\n<div id='displayArea'>\n <div id='messageArea'></div>\n <div id='tiddlerDisplay'></div>\n</div>\n<!--}}}-->\n
The tiddler 'New Tiddler' doesn't yet exist. Double-click to create it
! Another project or whatever\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && tiddler.tags.contains("ttSafeway")'\n sortBy\n 'tiddler.created'\n script\n 'function writeTaskLine(tiddler, index) {var result =""; if (index ==0) {result +="|!Done?|!Task|! |\sn";} result +="|<<dataCheckbox "+tiddler.title+" statusIsDone$))|"+tiddler.data("taskText")+" |[[(open)|"+tiddler.title+"]]|\sn"; return result;}'\n write\n 'writeTaskLine(tiddler,index)'\n>>\n\n!~TiddlyTracksProject\nTiddlyTracks has plenty of todo items! Bah!\n<<forEachTiddler\n where\n 'tiddler.tags.contains("tt_task") && !tiddler.tags.contains("ttSafeway")'\n sortBy\n 'tiddler.created'\n script\n 'function writeTaskLine(tiddler, index) {var result =""; if (index ==0) {result +="|!Done?|!Task|! |\sn";} result +="|<<dataCheckbox "+tiddler.title+" statusIsDone$))|"+tiddler.data("taskText")+" |[[(open)|"+tiddler.title+"]]|\sn"; return result;}'\n write\n 'writeTaskLine(tiddler,index)'\n>>\n
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>\n<<tiddler TiddlyTracksSideBar>>
by ChristineHodges (Using [[TiddlyWiki|http://www.tiddlywiki.com]] 2.0.2)
~TiddlyTracks 0.9 Beta
/***\n! Style Sheet: Clean Green\n|''Style Sheet Name:''|Clean Green|\n|''Version:''|1.0 FIREFOX ONLY (2006-01-29)|\n|''Source:''|http://www.tentacle.net/~psifi/tiddlytracks/#CleanGreenStyleSheet|\n|''Author:''|Christine Hodges (see Google Groups)|\n|''Tiddlers Required:''|PageTemplate, ViewTemplate (see AboutStyles)|\n|''TiddlyWiki:''|2.0|\n|''Browsers:''|Firefox only for now. Bah.|\n\n!Header /%==================================================%/\n***/\n/*{{{*/\n.header\n{\n clear: both;\n background: #707c51;\n color: #CCff99;\n font-family: trebuchet ms, veranda, georgia;\n}\n\n.headerForeground\n{\n color: #cadeb9;\n position: relative;\n padding: 2em 0em 1em 1em;\n}\n\n.headerForeground a\n{\n color: #cadeb9;\n}\n\n.siteTitle { font-weight: bold; font-size: 3em; }\n.siteSubtitle { font-weight: normal; font-size: 1.3em; }\n/*}}}*/\n\n/***\n!Horizontal Main Menu /%=====================================%/\nTop menu is based on MPTW (http://simonbaird.com/mptw/).\n***/\n/*{{{*/\n#topMenu\n{\n background: #fff;\n padding: 2px;\n}\n\n#topMenu .button, #topMenu .tiddlyLink\n{\n color: #333;\n font-weight: bold;\n font-size: 1.1em;\n text-decoration: none;\n letter-spacing: 1.5px;\n}\n\n#topMenu br { display: none; }\n \n#topMenu ul\n{\n /*float: right;*/\n right: 0; /* http://www.communitymx.com/content/article.cfm?cid=529B0 */\n padding: 0;\n margin: 0px 0px 15px 0px;\n list-style: none;\n}\n\n#topMenu ul li a {\n display: block;\n float: left;\n background: #cadeb9;\n padding: 5px 15px 5px 15px;\n margin: 2px 2px 2px 2px;\n text-align: center;\n}\n\n#topMenu ul li a:hover {\n color: #666600;\n border: 2px solid #666600;\n}\n\n#topMenu .button:hover { border: 2px solid #7CAF6B; }\n#displayArea { margin: 1em 15.7em 0em 1em; }\n\n/* so we use the freed up space */\n/* just in case want some QuickOpenTags in your topMenu */\n#topMenu .quickopentag\n{\n padding: 0px;\n margin: 0px;\n border: 0px;\n}\n\n#topMenu .quickopentag .tiddlyLink\n{\n padding-right: 1px;\n margin-right: 0px;\n}\n\n#topMenu .quickopentag .button\n{\n padding-left: 1px;\n margin-left: 0px;\n border: 0px;\n}\n\n/*}}}*/\n\n/***\n!General /%==================================================%/\n***/\n/*{{{*/\nh1 {\n color: #333;\n background: #cadeb9;\n padding: 2px;\n}\n\nh2 {\n color: #707c51;\n background: #fff;\n border-bottom: 2px dotted #cadeb9;\n padding: 2px;\n}\n\nh3 {\n color: #707c51;\n background: #fff;\n border-bottom: 1px dotted #cadeb9;\n padding: 2px;\n}\n\nh4, h5 {\n color: #707c51;\n background: #fff;\n padding: 1.5px;\n}\n\na{\n color: #666600; /* #707c51; */\n}\n\na:hover{\n background: #666600;\n color: #fff;\n}\n\n.button {\n color: #014;\n border: 1px solid #fff;\n}\n\n.button:hover {\n color: #014;\n background: #cadeb9;\n border: 1px solid #707c51;\n}\n\n.button:active {\n color: #fff;\n background: #707c51;\n border: 1px solid #333;\n}\n/*}}}*/\n\n/***\n!Tiddler and Task Tiddler Display /%========================================%/\n***/\n/*{{{*/\n.singleTiddlerContainer {\n border: 2px dashed #ccc;\n margin: 0px -10px 0px -10px;\n padding: 10px;\n/* for .tiddler: margin: 25px 5px 5px 0px; padding: 15px 10px 10px 10px; */\n}\n\n#ttTaskContainer {\n border: 2px dashed #cadeb9;\n margin: 0px -10px 0px -10px;\n padding: 10px 10px 10px 10px;\n}\n\n#ttTaskTitle {\n color: #333;\n font-weight: bold;\n font-family: georgia;\n}\n\n#ttTaskTitle .title {\n font-size: 1em;\n}\n\ndiv.ttTaskListText:hover {\n background: #fe8;\n}\n\n.ttTaskListText { /* filling cell */\n margin: -5px -2px -5px -2px;\n padding: 5px 3px 5px 3px;\n}\n\n.tagglyTagged li.listTitle { display:none;}\n.tagglyTagged li { display: inline; font-size:90%; }\n.tagglyTagged ul { margin:0px; padding:0px; }\n\n.tagging { float: none; width:40%; }\n\n#tiddlerDisplay { padding-bottom: 5px; }\n\n#tiddlerDisplay .title {\n color: #333;\n margin-bottom: 2px;\n margin-left: -3px;\n font-weight: bold;\n font-family: georgia;\n letter-spacing: 0.5px;\n}\n\n\n.subtitle {\n float: right;\n color: #866;\n margin-top: 5px;\n}\n/*}}}*/
A Getting Started Guide:\nrusslipton.com/tiddlyworks.html
/***\n| Name:|TagBasedTemplates|\n| Source:|http://simonbaird.com/mptw/#TagBasedTemplates|\n| Version:|Prototype (12-Jan-2006)|\n| Usage:|See [[FlipMeOver!]] for an example|\n***/\n//{{{\n\nconfig.templateChooser = {};\n\nfunction registerTemplate(tiddlerName,tagName) {\n config.templateChooser[tagName] = tiddlerName;\n}\n\n//registerTemplate("UpsideDownTemplate","UpsideDown");\n\nfunction checkTagTemplateRules(tags) {\n for (var t in config.templateChooser)\n for (var j=0; j<tags.length; j++)\n if (t == tags[j])\n return config.templateChooser[t];\n return null;\n}\n\nstory.chooseTemplateForTiddler = function(title,template) {\n if (!template) {\n var tiddler = store.getTiddler(title);\n if (tiddler) {\n var tagBasedTemplate = checkTagTemplateRules(store.getTiddler(title).tags);\n if (tagBasedTemplate)\n return tagBasedTemplate;\n }\n return config.tiddlerTemplates[DEFAULT_VIEW_TEMPLATE];\n }\n else \n return config.tiddlerTemplates[template];\n};\n\n//}}}\n
Avoid task tiddler viewing. Set something simple for those who insist ("Task Source Edit")\n\n~~\nview task\n* tags in edit mode (hide tt_task and exclude lists)\n* "delete task"\n* task ID: title\n\ntask tools: close close others\ntiddler tools:\n+editTtTiddler permalink references jump deleteTtTask\neditTtTiddler: updateTtTask -cancelTiddler deleteTtTask\n~~\n
<<forEachTiddler\nwhere\n'(1==1)'\nscript\n'function writeRow(index, tiddler, context) { var result = ""; if (index == 0) { context.ctitle ="TestFor"; } result+= "[["+context.ctitle+"]]"+" > "+tiddler.title +"\sn"; return result; } '\nwrite\n'writeRow(index, tiddler, context)'\n>>\n\n
The tiddler 'New Tiddler' doesn't yet exist. Double-click to create it.\n\n!Section one\nI like this Ethiopian spicy tomato lentil stew. from The Post Punk Kitchen. If you have to buy all the spices, the first time you make it might be a little pricey, but the other ingredients are way cheap, and you could probably get away with using a pre-made curry instead of the spice blend in the recipe. -posted by Airhen at 7:39 PM PST on January 25\n\nI second the dal. I am a vegetarian and constantly struggle with getting enough protein on my college budget. The cheapest solution I've found are lentils and rice. Just mix 1/4cup (250g) in the proper amount of water and boil. Add a tablespoon of sugar and a teaspoon of salt.\n\n!!Section one-two\nI like this Ethiopian spicy tomato lentil stew. from The Post Punk Kitchen. If you have to buy all the spices, the first time you make it might be a little pricey, but the other ingredients are way cheap, and you could probably get away with using a pre-made curry instead of the spice blend in the recipe.\nposted by Airhen at 7:39 PM PST on January 25\n\n!!Section one-two too\nI second the dal. I am a vegetarian and constantly struggle with getting enough protein on my college budget. The cheapest solution I've found are lentils and rice. Just mix 1/4cup (250g) in the proper amount of water and boil. Add a tablespoon of sugar and a teaspoon of salt.\n\n!!!Section one-two-three\nI like this Ethiopian spicy tomato lentil stew. from The Post Punk Kitchen. If you have to buy all the spices, the first time you make it might be a little pricey, but the other ingredients are way cheap, and you could probably get away with using a pre-made curry instead of the spice blend in the recipe. - posted by Airhen at 7:39 PM PST on January 25\n\n
Oh this is just some note...
Regular text only!
/***\n|''Name:''|TiddlyTracksPlugin|\n|''Version:''|0.9 BETA (2006-01-28)|\n|''Source:''|http://www.tentacle.net/~psifi/tiddlytracks/#TiddlyTracksPlugin|\n|''Author:''|Christine Hodges (see Google Groups)|\n|''Licence:''|[[BSD open source license]]|\n|''Macros:''|ttAddTask, dataCheckbox|\n|''Plugins Required:''|DataTiddlerPlugin, ForEachTiddlerPlugin, FormTiddlerPlugin, TagBasedTemplatesPlugin|\n|''Tiddlers Required:''|[[ttTaskViewTemplate]], [[ttTaskFormTemplate]], TiddlyTracksSideBar (see use in SideBarOptions)|\n|''Recommended:''|MasterTaskList (sample of viewing tasks; see also NextActions), [[Inbox]]|\n|''TiddlyWiki:''|2.0|\n|''Browser:''|Firefox|\n\n!Description\nTask manager that displays the complete task description in task lists with rapid input feature.\n\n!Additional Setup\nYou can add the rapid input text box ("add new task") to your sidebar menu by editing the SideBarOptions tiddler: copy and paste in {{{<<tiddler TiddlyTracksSideBar>>}}}.\n\n!The Basics So Far\n* Type something in the ''add new task'' text box and press "Enter". Your text will show up on the MasterTaskList (and [[Inbox]] if you copy that tiddler).\n* Or, type some tags names in standard tag edit format followed by ";;;" then the task and the task will have those tags. Example: "urgent call;;;call Jim re: movie". If you do not specify tags, the task will be tagged "in" (for "[[Inbox]]").\n* Edit task by clicking on it in MasterTaskList.\n* Copy the master task list forEachTiddler to make your our tag-based task lists. Be sure to tag the tiddler with "''tt_taskList''" (so that it will refresh properly).\n* You could also tag an existing tiddler with "tt_task" and the text of that tiddler will show up as a task. (But from this point forward you must edit it in tt_task edit mode OR press "edit source" to edit in standard edit mode.)\n\n!Code\n\n!! General utilities other plugins may want\n***/\n//{{{\n// TODO don't refresh if it is being edited\n/** Refreshes story tiddlers that have any of the tags listed in tagList. */\nwindow.refreshTagged = function refreshTagged(tagList) {\n story.forEachTiddler(function(title,element) {\n var tiddlerTags = store.getTiddler(title).tags;\n for (var i=0; i<tiddlerTags.length; i++) {\n if (tagList.contains(tiddlerTags[i])) {\n story.refreshTiddler(title,false,true);\n continue; // refresh it once only\n }\n }\n });\n}\n\nconfig.commands.editSource = {\n text: "edit source",\n tooltip: "Edit tiddler in standard edit mode",\n handler: function(event,src,title) {\n story.refreshTiddler(title,DEFAULT_EDIT_TEMPLATE,true); // standard editTiddler didn't work. must force refresh?\n }\n};\n\n\n//}}}\n\n/***\n!! ~TiddlyTracks-specific\n***/\n//{{{\nconfig.commands.closeTaskAndRefresh = {\n text: "close",\n tooltip: "Close this task tiddler",\n handler: function(event,src,title) {\n story.closeTiddler(title,true,event.shiftKey || event.altKey);\n refreshTagged([config.macros.tiddlyTracks.TASK_LIST_TAG]);\n }\n};\n\n// TODO make this option-al\nregisterTemplate("ttTaskViewTemplate", "tt_task");\n\nfunction deleteTtTask(e, src, title) {\n if (!title) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n title = target.getAttribute("tiddler");\n }\n config.commands.deleteTiddler.handler(e,src,title);\n refreshTagged([config.macros.tiddlyTracks.TASK_LIST_TAG]);\n}\n\nconfig.commands.ttDeleteTask = {\n text: "delete task",\n tooltip: "Delete this task",\n handler: function(event,src,title) {\n deleteTtTask(event, src, title);\n }\n};\n\nconfig.commands.ttSaveTask = {\n text: "save",\n tooltip: "Save this task",\n handler: function(event,src,title) {\n config.commands.saveTiddler.handler(event, src, title);\n // TODO Udo's plugin does data save automatically but need to coordinate checkboxes in both directions look at form fields\n var target = resolveTarget(event);\n var allEls = story.findContainingTiddler(target).getElementsByTagName("*");\n var fields = config.macros.tiddlyTracks.TASK_FIELDS;\n for (var i = 0; i<allEls.length; i++) {\n var element = allEls[i];\n if (fields.find(element.name)) {\n DataTiddler.setData(title, element.name, element.value);\n }\n }\n refreshTagged([config.macros.tiddlyTracks.TASK_LIST_TAG]);\n }\n};\n\nconfig.macros.forEachTiddler.actions.writeTtTaskLine = {\n handler: function(place, tiddlers, parameter, context) {\n var wrapper = document.createElement("div"); // TODO id=containingTiddler and class=taskList for task list\n place.appendChild(wrapper);\n var text = "";\n for (var i=0; i<tiddlers.length; i++) {\n var tiddler = tiddlers[i];\n var title = tiddler.title;\n var taskText = (tiddler.data("taskText")) ? tiddler.data("taskText") : tiddler.text;\n if (i == 0) { text +="|!~~"+config.macros.tiddlyTracks.TABLE_HEADING_DONE+"~~|!"+config.macros.tiddlyTracks.TABLE_HEADING_TASK+"|!~~"+config.macros.tiddlyTracks.TABLE_HEADING_DELETE+"~~|\sn"; } // TODO are apostophes allowed in tiddler title?\n var deleteButton = "<html><input id='ttTaskDelete' type='submit' value='X' onclick='deleteTtTask(event)' tiddler='"+title+"' style='color:#660000; padding: 0; font-family:Arial Black; background-color:#fff; border:none' /> </html>";\n text +="| <<dataCheckbox "+title+" statusIsDone>> "+\n "|<html><div class='ttTaskListText' refresh='link' tiddlyLink='"+title+"' onclick='onClickTiddlerLink(event)'>"+taskText+"</div></html>"+\n "| "+deleteButton+" |\sn";\n }\n wikify(text, wrapper);\n }\n};\n\n\nconfig.macros.tiddlyTracks = {\n label: "tiddlyTracks",\n version: {major: 1, minor: 0, revision: 0, date: new Date(2006, 1, 15)},\n prompt: "tiddlyTracks currently just holds variables",\n \n // Particular properities\n DEFAULT_INBOX_TAG: "in",\n TASK_LIST_TAG: "tt_taskList",\n TASK_TEMPLATE: "ttTaskFormTemplate",\n TASK_TITLE_PREFIX: "tt_task_",\n TASK_DEFAULT_TAGS: ["tt_task","excludeLists"],\n TASK_STATUS_NAME: "statusIsDone",\n TASK_TEXT_NAME: "taskText",\n TASK_FIELDS: [this.TASK_STATUS_NAME, this.TASK_TEXT_NAME],\n \n // Messages, prompts, etc.\n TABLE_HEADING_DONE: "Done",\n TABLE_HEADING_TASK: "Task",\n TABLE_HEADING_DELETE: "Delete"\n};\n\n///////////////////////\n// "Add New Task" box\n///////////////////////\nconfig.macros.ttAddTask = {\n label: "ttAddTask",\n version: {major: 1, minor: 0, revision: 0, date: new Date(2005, 12, 31)},\n prompt: "Display a text box for quickly entering TiddlyTracks tasks: ttAddTask [textBoxWidth]",\n \n // Particular properities\n BOX_ID: "ttAddTask",\n DEFAULT_VALUE: "", // "Add New Task",\n DEFAULT_WIDTH: 15,\n TAGS_MARKER: ";;;"\n};\n\nconfig.macros.ttAddTask.handler = function(place,macroName,params) {\n // TODO params for width and value. var taskBoxWidth = (params[0]) ? params[0] : this.DEFAULT_WIDTH;\n var text = "<html><input type='text' autocomplete='off' id='"+this.BOX_ID+\n "' name='"+config.macros.tiddlyTracks.TASK_TEXT_NAME+\n "' size='"+this.DEFAULT_WIDTH+\n "' onkeyup='keyUpTtTaskEntry(event)' value='"+this.DEFAULT_VALUE+"'/></html>";\n wikify(text, place);\n}\n\n// basically make an empty key uniquely-named tiddler\nfunction newTtTaskTiddler(formTemplateName, tiddlerTitlePrefix, tags) {\n var tiddler = new Tiddler();\n var tiddlerName = tiddlerTitlePrefix + (new Date()).convertToYYYYMMDDHHMMSSMMM();\n var body = "<<formTiddler [["+formTemplateName+"]]>>";\n var newTags = []; // copy array\n for (var i=0;i<tags.length;i++) { newTags.push(tags[i]); }\n tiddler.set(tiddlerName,body,config.options.txtUserName,new Date(),newTags);\n return tiddler;\n}\n\n// Respond to entering a task in a text box/textarea\nfunction keyUpTtTaskEntry(e) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n if (e.keyCode == 27) { // Esc = cancel, reset\n target.value = "";\n } else if (e.keyCode == 13) { // Enter = submit: make new task tiddler and save it\n if (!target.value) { return false; }\n var t = newTtTaskTiddler(config.macros.tiddlyTracks.TASK_TEMPLATE,\n config.macros.tiddlyTracks.TASK_TITLE_PREFIX,\n config.macros.tiddlyTracks.TASK_DEFAULT_TAGS);\n var taskText = target.value;\n var posTagsEnd = taskText.indexOf(config.macros.ttAddTask.TAGS_MARKER);\n if (posTagsEnd == -1) {\n t.tags.pushUnique(config.macros.tiddlyTracks.DEFAULT_INBOX_TAG);\n } else {\n var moreTags = taskText.substr(0, posTagsEnd).readBracketedList(true);\n for (var i=0; i<moreTags.length;i++) {\n t.tags.pushUnique(moreTags[i]);\n }\n taskText = taskText.substr(posTagsEnd+config.macros.ttAddTask.TAGS_MARKER.length);\n taskText = taskText.replace( /^\ss+/g, "" ); //trim leading space\n }\n store.saveTiddler(t.title,t.title,t.text,config.options.txtUserName,new Date(),t.tags);\n DataTiddler.setData(t.title, target.name, taskText);\n target.value = "";\n refreshTagged([config.macros.tiddlyTracks.TASK_LIST_TAG]);\n }\n return false;\n }\n\n//////////////////////////////\n// Data Checkbox\n//////////////////////////////\nconfig.macros.dataCheckbox = {\n label: "dataCheckbox",\n version: {major: 1, minor: 0, revision: 0, date: new Date(2005, 12, 31)},\n prompt: "Create a checkbox tied to the data section of any tiddler. Usage: dataCheckbox tiddlerName checkboxName",\n SEP: "_",\n ID_PREFIX: "dc"\n};\n\nconfig.macros.dataCheckbox.handler = function(place,macroName,params) {\n if (params.length < 2) {\n createTiddlyElement(place,"span",null,"dataCheckboxError","Macro Error: Missing argument(s). Provide tiddler and checkbox names.");\n }\n var tiddler = store.getTiddler(params[0]);\n var checkboxName = params[1];\n var title = tiddler.title;\n var c = createTiddlyElement(place, "input", null, null, null);\n c.setAttribute("id", config.macros.dataCheckbox.ID_PREFIX+this.SEP+title+this.SEP+checkboxName);\n c.setAttribute("type", "checkbox");\n c.setAttribute("name", checkboxName);\n c.setAttribute("tiddler", title);\n c.checked = DataTiddler.getData(tiddler,checkboxName,undefined);\n c.setAttribute("onclick", "onExistingDataUpdate(event)");\n}\n\nfunction onExistingDataUpdate(e) {\n if (!e) var e = window.event;\n var target = resolveTarget(e);\n var tiddlerName = target.getAttribute("tiddler")\n var getter = config.macros.formTiddler.getter[target.type];\n DataTiddler.setData(tiddlerName, target.name, getter(target));\n refreshTagged([config.macros.tiddlyTracks.TASK_LIST_TAG]); // TODO maybe checkbox accepts any event function\n}\n//}}}
~~add new task~~\n<<ttAddTask>>\n[[View All Tasks|MasterTaskList]]\n
<div class='singleTiddlerContainer'>\n<div class='toolbar' macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump'></div>\n<div class='subtitle'><span macro='view modified date [[DD MMM YYYY]]'></span> </div>\n<div class='tagglyTagged' macro="tags"></div>\n<div class='title' macro='view title'></div>\n<div class='viewer' macro='view text wikified'></div>\n<div class='tagging' macro='tagging'></div>\n</div>
check it out;;;\n\n;;;cef;;;\n\n;;;asdf
<<forEachTiddler\n where\n'(1==1)'\n script\n 'context.callingTiddlerName = story.findContainingTiddler(context.place).id.substr(story.idPrefix.length)'\n write\n '"* [["+tiddler.title+"]] (in [["+context.callingTiddlerName+"]])\sn"'>>\n\n
<html>\n<input name="statusIsDone" type="checkbox" /> \n<textarea name="taskText" rows="2" cols="80"></textarea>\n</html><data>{"titlePrefix":"tt_task_","defaultTags":["tt_task","excludeLists"]}</data>
<div id='ttTaskContainer'>\n<div class='toolbar' macro='toolbar +ttSaveTask closeTaskAndRefresh editSource permalink references ttDeleteTask'></div>\n<div id='ttTaskTitle'>\n <div class='ttTaskTitlePrefix'>Task ID: </div>\n <div class='title' macro='view title'></div><br/>\n</div>\n <div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (created <span macro='view created date [[DD MMM YYYY]]'></span>)</div>\n<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>\n<div class='tagging' macro='tagging'></div>\n<div class='viewer' macro='view text wikified'></div>\n</div>\n
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"add link to installation to AboutStyles"}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"do inbox versus master list","statusIsDone":true}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"mark re: boston trip"}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"tere re: send my hat up"}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"test in"}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"IE!!!!!"}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"want click menu item = open tiddler at top even if it's already open somewhere"}</data>
<<formTiddler [[ttTaskFormTemplate]]>><data>{"taskText":"investigate references for refresh. build test cases for discussion."}</data>
<<formTiddler [[MasterTaskFormTemplate]]>><data>{"taskText":"file watching. how does eclipse constantly watch for file modification?"}</data>